iterator = this.iterator(true);
while (iterator.hasNext()) {
@@ -636,8 +634,6 @@ public class Rocket extends RocketComponent {
//////// Obligatory component information
-
-
@Override
public String getComponentName() {
//// Rocket
diff --git a/core/src/net/sf/openrocket/rocketcomponent/RocketComponent.java b/core/src/net/sf/openrocket/rocketcomponent/RocketComponent.java
index 67538f5b1..297154a85 100644
--- a/core/src/net/sf/openrocket/rocketcomponent/RocketComponent.java
+++ b/core/src/net/sf/openrocket/rocketcomponent/RocketComponent.java
@@ -106,8 +106,14 @@ public abstract class RocketComponent implements ChangeSource, Cloneable, Iterab
* Offset of the position of this component relative to the normal position given by
* relativePosition. By default zero, i.e. no position change.
*/
- protected double position = 0;
+ // protected double position = 0;
+ /**
+ * Position of this component relative to it's parent.
+ * In case (null == parent ): i.e. the Rocket/root component, the position is constrained to 0,0,0, and is the reference origin for the entire rocket.
+ * Defaults to (0,0,0)
+ */
+ protected Coordinate position = new Coordinate();
// Color of the component, null means to use the default color
private Color color = null;
@@ -653,8 +659,14 @@ public abstract class RocketComponent implements ChangeSource, Cloneable, Iterab
return isCGOverridden() || isMassOverridden();
}
-
-
+ /**
+ * placeholder. This allows code to generally test if this component represents multiple instances with just one function call.
+ *
+ * @return number of instances
+ */
+ public int getInstanceCount() {
+ return 1;
+ }
/**
* Get the user-defined name of the component.
@@ -844,6 +856,10 @@ public abstract class RocketComponent implements ChangeSource, Cloneable, Iterab
return length;
}
+ public RocketComponent.Position getRelativePositionMethod() {
+ return this.relativePosition;
+ }
+
/**
* Get the positioning of the component relative to its parent component.
* This is one of the enums of {@link Position}. A setter method is not provided,
@@ -867,41 +883,12 @@ public abstract class RocketComponent implements ChangeSource, Cloneable, Iterab
* @param position the relative positioning.
*/
protected void setRelativePosition(RocketComponent.Position position) {
- if (this.relativePosition == position)
- return;
- checkState();
-
- // Update position so as not to move the component
- if (this.parent != null) {
- double thisPos = this.toRelative(Coordinate.NUL, this.parent)[0].x;
-
- switch (position) {
- case ABSOLUTE:
- this.position = this.toAbsolute(Coordinate.NUL)[0].x;
- break;
-
- case TOP:
- this.position = thisPos;
- break;
-
- case MIDDLE:
- this.position = thisPos - (this.parent.length - this.length) / 2;
- break;
-
- case BOTTOM:
- this.position = thisPos - (this.parent.length - this.length);
- break;
-
- default:
- throw new BugException("Unknown position type: " + position);
- }
- }
+ // this variable does not change the internal representation
+ // the relativePosition (method) is just the lens through which external code may view this component's position.
this.relativePosition = position;
- fireComponentChangeEvent(ComponentChangeEvent.BOTH_CHANGE);
}
-
/**
* Determine position relative to given position argument. Note: This is a side-effect free method. No state
* is modified.
@@ -912,22 +899,34 @@ public abstract class RocketComponent implements ChangeSource, Cloneable, Iterab
* @return double position of the component relative to the parent, with respect to position
*/
public double asPositionValue(Position thePosition, RocketComponent relativeTo) {
- double result = this.position;
+ double result = this.position.x; // relative
+ // this should be the usual case.... only 'Stage' classes should call this with anything else....
+ double relativeAxialPosition = this.position.x;
+ if (relativeTo != this.parent) {
+ Coordinate refAbsPos = relativeTo.getAbsolutePositionVector();
+ Coordinate curAbsPos = this.getAbsolutePositionVector();
+ relativeAxialPosition = (curAbsPos.x - refAbsPos.x);
+ }
+
if (relativeTo != null) {
- double thisPos = this.toRelative(Coordinate.NUL, relativeTo)[0].x;
+ double relLength = relativeTo.getLength();
switch (thePosition) {
+ case AFTER:
+ result = relativeAxialPosition + (-relLength - this.getLength()) / 2;
+ break;
case ABSOLUTE:
- result = this.toAbsolute(Coordinate.NUL)[0].x;
+ Coordinate curAbsPos = this.getAbsolutePositionVector();
+ result = curAbsPos.x;
break;
case TOP:
- result = thisPos;
+ result = relativeAxialPosition + (relLength - this.getLength()) / 2;
break;
case MIDDLE:
- result = thisPos - (relativeTo.length - this.length) / 2;
+ result = relativeAxialPosition;
break;
case BOTTOM:
- result = thisPos - (relativeTo.length - this.length);
+ result = relativeAxialPosition + (this.length - relLength) / 2;
break;
default:
throw new BugException("Unknown position type: " + thePosition);
@@ -942,59 +941,144 @@ public abstract class RocketComponent implements ChangeSource, Cloneable, Iterab
*
* @return the positional value.
*/
- public final double getPositionValue() {
- mutex.verify();
- return position;
+ public double getPositionValue() {
+ return this.getAxialOffset();
}
+ public double getAxialOffset() {
+ mutex.verify();
+ return this.asPositionValue(this.relativePosition, this.parent);
+ }
+
+ /**
+ *
+ * @return always returns false for base components. This enables one-line testing if a component is on the rocket center-line or not.
+ */
+ public boolean isCenterline() {
+ return true;
+ }
+
+ public boolean isAncestor(final RocketComponent testComp) {
+ RocketComponent curComp = testComp.parent;
+ while (curComp != null) {
+ if (this == curComp) {
+ return true;
+ }
+ curComp = curComp.parent;
+ }
+ return false;
+ }
+
/**
* Set the position value of the component. The exact meaning of the value
* depends on the current relative positioning.
*
- * The default implementation is of protected visibility, since many components
- * do not support setting the relative position. A component that does support
+ * Mince many components do not support setting the relative position. A component that does support
* it should override this with a public method that simply calls this
* supermethod AND fire a suitable ComponentChangeEvent.
- *
+ *
+ * @deprecated name is ambiguous in three-dimensional space: value may refer to any of the three dimensions. Please use 'setPositionX' instead.
+ *
* @param value the position value of the component.
*/
public void setPositionValue(double value) {
- if (MathUtil.equals(this.position, value))
+ // if (MathUtil.equals(this.position.x, value))
+ // return;
+ // // checkState();
+ // // this.position = new Coordinate(value, 0, 0);
+ setAxialOffset(value);
+ }
+
+ public void setAxialOffset(double value) {
+ this.setAxialOffset(this.relativePosition, value, this.getParent());
+ this.fireComponentChangeEvent(ComponentChangeEvent.BOTH_CHANGE);
+ }
+
+ protected void setAxialOffset(Position positionMethod, double newOffset, RocketComponent referenceComponent) {
+ // if this is the root of a hierarchy, constrain the position to zeros.
+ // if referenceComponent is null, the function call is simply in error
+
+ if ((null == this.parent) || (referenceComponent == null)) {
return;
+ }
+ if (referenceComponent == this) {
+ throw new BugException("cannot move a component relative to itself!");
+ }
checkState();
- this.position = value;
+ // if (this instanceof Stage) {
+ // System.err.println(String.format(" Setting Stage X offs: type: %s pos: %f <== (%s,%f,%s)", this.relativePosition.name(), this.position.x,
+ // positionMethod.name(), newOffset, referenceComponent.getName()));
+ // }
+
+ double newAxialPosition = Double.NaN;
+ double refRelX = referenceComponent.position.x;
+ double refLength = referenceComponent.getLength();
+
+ if (referenceComponent.isAncestor(this)) {
+ referenceComponent = this.parent;
+ refRelX = 0;
+ }
+
+ switch (positionMethod) {
+ case ABSOLUTE:
+ newAxialPosition = newOffset - this.parent.position.x;
+ break;
+ case AFTER:
+ newAxialPosition = refRelX + (refLength + this.length) / 2;
+ break;
+ case TOP:
+ newAxialPosition = refRelX + (-refLength + this.length) / 2 + newOffset;
+ break;
+ case MIDDLE:
+ newAxialPosition = refRelX + newOffset;
+ break;
+ case BOTTOM:
+ newAxialPosition = refRelX + (+refLength - this.length) / 2 + newOffset;
+ break;
+ default:
+ throw new BugException("Unknown position type: " + positionMethod);
+ }
+
+ this.position = new Coordinate(newAxialPosition, this.position.y, this.position.z);
+
+ // if ((this instanceof Stage) && (2 == this.getStageNumber())) {
+ // System.err.println(String.format(" Set Stage X offs: type: %s pos: %f", this.relativePosition.name(), this.position.x));
+ // }
}
-
- /*
- *
- */
public Coordinate getRelativePositionVector() {
- // ghetto version of this....
- return new Coordinate(this.getPositionValue(), 0, 0);
+ return this.position;
}
+ // disabled
+ // public void setRelativePositionVector(final Coordinate _newPos) {
+ // // this.setPosition( this.relativePosition, _newPos );
+ // }
- /*
- *
- */
- public void setRelativePositionVector(final Coordinate _newPos) {
- // ghetto version of this....
- this.position = _newPos.x;
+ public Coordinate getAbsolutePositionVector() {
+ if (null == this.parent) { // i.e. root / Rocket instance OR improperly initialized components
+ return new Coordinate();
+ } else {
+ return this.parent.getAbsolutePositionVector().add(this.getRelativePositionVector());
+ }
}
/////////// Coordinate changes ///////////
/**
- * Returns coordinate c in absolute coordinates. Equivalent to toComponent(c,null).
+ * Returns coordinate c in absolute/global/rocket coordinates. Equivalent to toComponent(c,null).
+ *
+ * @param c Coordinate in the component's coordinate system.
+ * @return an array of coordinates describing c
in global coordinates.
*/
public Coordinate[] toAbsolute(Coordinate c) {
- checkState();
- return toRelative(c, null);
+ // checkState();
+ // return toRelative(c, null);
+ Coordinate absCoord = this.getAbsolutePositionVector().add(c);
+ return new Coordinate[] { absCoord };
}
-
/**
* Return coordinate c
described in the coordinate system of
* dest
. If dest
is null
returns
@@ -1006,16 +1090,24 @@ public abstract class RocketComponent implements ChangeSource, Cloneable, Iterab
*
* The current implementation does not support rotating components.
*
+ * @deprecated to test alternate interface...
* @param c Coordinate in the component's coordinate system.
* @param dest Destination component coordinate system.
* @return an array of coordinates describing c
in coordinates
* relative to dest
.
*/
+ @Deprecated
public final Coordinate[] toRelative(Coordinate c, RocketComponent dest) {
checkState();
mutex.lock("toRelative");
+
+ if (null == dest) {
+ throw new BugException("calling toRelative(c,null) is being refactored. ");
+ }
+
try {
double absoluteX = Double.NaN;
+ double relativeX = 0;
double relativeY = 0;
double relativeZ = 0;
RocketComponent search = dest;
@@ -1023,15 +1115,6 @@ public abstract class RocketComponent implements ChangeSource, Cloneable, Iterab
array[0] = c;
RocketComponent component = this;
- if (component instanceof OutsideComponent) {
- OutsideComponent ext = (OutsideComponent) component;
- double phi = ext.getAngularPosition();
- double r = ext.getRadialPosition();
- relativeY = r * Math.cos(phi);
- relativeZ = r * Math.sin(phi);
- array[0].setY(relativeY);
- array[0].setZ(relativeZ);
- }
while ((component != search) && (component.parent != null)) {
array = component.shiftCoordinates(array);
@@ -1039,25 +1122,28 @@ public abstract class RocketComponent implements ChangeSource, Cloneable, Iterab
switch (component.relativePosition) {
case TOP:
for (int i = 0; i < array.length; i++) {
- array[i] = array[i].add(component.position, relativeY, relativeZ);
+ 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(component.position +
- (component.parent.length - component.length) / 2, relativeY, relativeZ);
+ 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(component.position +
- (component.parent.length - component.length), relativeY, relativeZ);
+ 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);
@@ -1069,7 +1155,7 @@ public abstract class RocketComponent implements ChangeSource, Cloneable, Iterab
}
}
for (int i = 0; i < array.length; i++) {
- array[i] = array[i].add(component.position + component.parent.length, relativeY, relativeZ);
+ array[i] = array[i].add(relativeX + component.parent.length, relativeY, relativeZ);
}
break;
@@ -1077,7 +1163,7 @@ public abstract class RocketComponent implements ChangeSource, Cloneable, Iterab
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 = component.position;
+ absoluteX = relativeX;
}
break;
@@ -1099,9 +1185,10 @@ public abstract class RocketComponent implements ChangeSource, Cloneable, Iterab
// 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.toAbsolute(Coordinate.NUL);
+
+ Coordinate origin = dest.getAbsolutePositionVector();
for (int i = 0; i < array.length; i++) {
- array[i] = array[i].sub(origin[0]);
+ array[i] = array[i].sub(origin);
}
}
@@ -1111,9 +1198,29 @@ public abstract class RocketComponent implements ChangeSource, Cloneable, Iterab
}
}
+ // public final Coordinate[] toRelative(Coordinate[] coords, RocketComponent dest) {
+ // Coordinate[] toReturn = new Coordinate[coords.length];
+ //
+ //
+ // // Coordinate[] array = new Coordinate[] { c };
+ // // // if( dest.isCluster() ){
+ // // // if( dest.multiplicity > 1){
+ // // array = dest.shiftCoordinates(array);
+ // // return this.toRelative(array, dest);
+ // // // }
+ //
+ // Coordinate destCenter = dest.getAbsolutePositionVector();
+ // Coordinate thisCenter = this.getAbsolutePositionVector();
+ // Coordinate relVector = destCenter.sub(thisCenter);
+ //
+ // for (int coord_index = 0; coord_index < coords.length; coord_index++) {
+ // toReturn[coord_index] = coords[coord_index].add(relVector);
+ // }
+ // return toReturn;
+ // }
/**
- * Recursively sum the lengths of all subcomponents that have position
+ * Iteratively sum the lengths of all subcomponents that have position
* Position.AFTER.
*
* @return Sum of the lengths.
@@ -1227,7 +1334,6 @@ public abstract class RocketComponent implements ChangeSource, Cloneable, Iterab
addChild(component, children.size());
}
-
/**
* Adds a child to the rocket component tree. The component is added to
* the given position of the component's child list.
@@ -1258,7 +1364,6 @@ public abstract class RocketComponent implements ChangeSource, Cloneable, Iterab
throw new IllegalStateException("Component " + component.getComponentName() +
" not currently compatible with component " + getComponentName());
}
-
children.add(index, component);
component.parent = this;
@@ -1282,6 +1387,7 @@ public abstract class RocketComponent implements ChangeSource, Cloneable, Iterab
this.checkComponentStructure();
component.checkComponentStructure();
+ updateBounds();
fireAddRemoveEvent(component);
}
@@ -1303,6 +1409,7 @@ public abstract class RocketComponent implements ChangeSource, Cloneable, Iterab
this.checkComponentStructure();
component.checkComponentStructure();
+ updateBounds();
fireAddRemoveEvent(component);
return true;
}
@@ -1327,6 +1434,7 @@ public abstract class RocketComponent implements ChangeSource, Cloneable, Iterab
this.checkComponentStructure();
component.checkComponentStructure();
+ updateBounds();
fireAddRemoveEvent(component);
}
}
@@ -1737,6 +1845,14 @@ public abstract class RocketComponent implements ChangeSource, Cloneable, Iterab
return id.hashCode();
}
+ /**
+ * the default implementation is mostly a placeholder here, however in inheriting classes,
+ * this function is useful to indicate adjacent placements and view sizes
+ */
+ protected void updateBounds() {
+ return;
+ }
+
///////////// Visitor pattern implementation
public R accept(RocketComponentVisitor visitor) {
visitor.visit(this);
@@ -1961,4 +2077,16 @@ public abstract class RocketComponent implements ChangeSource, Cloneable, Iterab
}
}
+ // Primarily for debug use
+ public void dumpTree(final boolean includeHeader, final String prefix) {
+ if (includeHeader) {
+ System.err.println(" [Name] [Length] [Rel Pos] [Abs Pos] ");
+ }
+
+ System.err.println(String.format("%s >> %-24s %5.3f %24s %24s", prefix, this.getName(), this.getLength(), this.getRelativePositionVector(), this.getAbsolutePositionVector()));
+ Iterator iterator = this.children.iterator();
+ while (iterator.hasNext()) {
+ iterator.next().dumpTree(false, prefix + " ");
+ }
+ }
}
diff --git a/core/src/net/sf/openrocket/rocketcomponent/Stage.java b/core/src/net/sf/openrocket/rocketcomponent/Stage.java
index d22d051e4..c75a93517 100644
--- a/core/src/net/sf/openrocket/rocketcomponent/Stage.java
+++ b/core/src/net/sf/openrocket/rocketcomponent/Stage.java
@@ -1,13 +1,16 @@
package net.sf.openrocket.rocketcomponent;
+import java.util.Iterator;
+
import net.sf.openrocket.l10n.Translator;
import net.sf.openrocket.startup.Application;
+import net.sf.openrocket.util.BugException;
import net.sf.openrocket.util.Coordinate;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
-public class Stage extends ComponentAssembly implements FlightConfigurableComponent, MultipleComponent, OutsideComponent {
+public class Stage extends ComponentAssembly implements FlightConfigurableComponent, OutsideComponent {
static final Translator trans = Application.getTranslator();
private static final Logger log = LoggerFactory.getLogger(Stage.class);
@@ -17,7 +20,7 @@ public class Stage extends ComponentAssembly implements FlightConfigurableCompon
private boolean outside = false;
private double angularPosition_rad = 0;
private double radialPosition_m = 0;
- private int stageRelativeTo = 0;
+ private Stage stageRelativeTo = null;
private int count = 1;
private double angularSeparation = Math.PI;
@@ -25,15 +28,72 @@ public class Stage extends ComponentAssembly implements FlightConfigurableCompon
public Stage() {
this.separationConfigurations = new FlightConfigurationImpl(this, ComponentChangeEvent.EVENT_CHANGE, new StageSeparationConfiguration());
+ this.relativePosition = Position.AFTER;
}
+ @Override
+ protected void componentChanged(ComponentChangeEvent e) {
+ checkState();
+
+ if (e.isAerodynamicChange() || e.isMassChange()) {
+ // System.err.println(">> in (" + this.getStageNumber() + ")" + this.getName());
+ // update this component
+ this.updateBounds();
+ this.updateCenter();
+
+ // now update children relative to this
+ int childIndex = 0;
+ int childCount = this.getChildCount();
+ RocketComponent prevComp = null;
+ while (childIndex < childCount) {
+ RocketComponent curComp = this.getChild(childIndex);
+ // System.err.println(" updating position of " + curComp + " via (AFTER, O, " + prevComp + ")");
+ if (0 == childIndex) {
+ curComp.setAxialOffset(Position.TOP, 0, this);
+ } else {
+ if (Position.AFTER != curComp.getRelativePositionMethod()) {
+ throw new IllegalStateException(" direct children of a Stage are expected to be positioned via AFTER.");
+ }
+ curComp.setAxialOffset(Position.AFTER, 0, prevComp);
+ }
+ // System.err.println(" position updated to: " + curComp.getAxialOffset());
+
+ prevComp = curComp;
+ childIndex++;
+ }
+
+
+ }
+ }
+
+ protected String toPositionString() {
+ return ">> " + this.getName() + " rel: " + this.getRelativePositionVector().x + " abs: " + this.getAbsolutePositionVector().x;
+ }
+
+ protected void dumpDetail() {
+ StackTraceElement[] stackTrace = (new Exception()).getStackTrace();
+ System.err.println(" >> Dumping Stage Detailed Information from: " + stackTrace[1].getMethodName());
+ System.err.println(" curStageName: " + this.getName());
+ System.err.println(" method: " + this.relativePosition.name());
+ System.err.println(" thisCenterX: " + this.position.x);
+ System.err.println(" this length: " + this.length);
+ if (-1 == this.getRelativeToStage()) {
+ System.err.println(" ..refStageName: " + null);
+ } else {
+ Stage refStage = this.stageRelativeTo;
+ System.err.println(" ..refStageName: " + refStage.getName());
+ System.err.println(" ..refCenterX: " + refStage.position.x);
+ System.err.println(" ..refLength: " + refStage.getLength());
+ }
+ }
+
+
@Override
public String getComponentName() {
//// Stage
return trans.get("Stage.Stage");
}
-
public FlightConfiguration getStageSeparationConfiguration() {
return separationConfigurations;
}
@@ -74,18 +134,26 @@ public class Stage extends ComponentAssembly implements FlightConfigurableCompon
return this.outside;
}
- public boolean isInline() {
+ @Override
+ public boolean isCenterline() {
return !this.outside;
}
@Override
public void setOutside(final boolean _outside) {
- this.outside = _outside;
- if (Position.AFTER == this.relativePosition) {
- this.relativePosition = Position.BOTTOM;
- this.position = 0;
+ if (this.outside == _outside) {
+ return;
}
- if (!this.outside) {
+
+ this.outside = _outside;
+ if (this.outside) {
+ this.relativePosition = Position.BOTTOM;
+ if (null == this.stageRelativeTo) {
+ this.stageRelativeTo = this.updatePrevAxialStage();
+ }
+ } else {
+ this.relativePosition = Position.AFTER;
+ this.stageRelativeTo = this.updatePrevAxialStage();
this.count = 1;
}
@@ -93,8 +161,8 @@ public class Stage extends ComponentAssembly implements FlightConfigurableCompon
}
@Override
- public int getCount() {
- if (this.isInline()) {
+ public int getInstanceCount() {
+ if (this.isCenterline()) {
return 1;
} else {
return this.count;
@@ -102,7 +170,7 @@ public class Stage extends ComponentAssembly implements FlightConfigurableCompon
}
@Override
- public void setCount(final int _count) {
+ public void setInstanceCount(final int _count) {
mutex.verify();
this.count = _count;
this.angularSeparation = Math.PI * 2 / this.count;
@@ -113,7 +181,7 @@ public class Stage extends ComponentAssembly implements FlightConfigurableCompon
}
@Override
- public double getAngularPosition() {
+ public double getAngularOffset() {
if (this.outside) {
return this.angularPosition_rad;
} else {
@@ -123,7 +191,7 @@ public class Stage extends ComponentAssembly implements FlightConfigurableCompon
}
@Override
- public void setAngularPosition(final double angle_rad) {
+ public void setAngularOffset(final double angle_rad) {
this.angularPosition_rad = angle_rad;
if (this.outside) {
fireComponentChangeEvent(ComponentChangeEvent.BOTH_CHANGE);
@@ -131,7 +199,7 @@ public class Stage extends ComponentAssembly implements FlightConfigurableCompon
}
@Override
- public double getRadialPosition() {
+ public double getRadialOffset() {
if (this.outside) {
return this.radialPosition_m;
} else {
@@ -140,7 +208,7 @@ public class Stage extends ComponentAssembly implements FlightConfigurableCompon
}
@Override
- public void setRadialPosition(final double radius) {
+ public void setRadialOffset(final double radius) {
this.radialPosition_m = radius;
// log.error(" set radial position for: " + this.getName() + " to: " + this.radialPosition_m + " ... in meters?");
if (this.outside) {
@@ -148,6 +216,25 @@ public class Stage extends ComponentAssembly implements FlightConfigurableCompon
}
}
+ public void setRelativePositionMethod(final Position _newPosition) {
+ if (Position.AFTER != _newPosition) {
+ this.outside = true;
+ }
+
+ super.setRelativePosition(_newPosition);
+ }
+
+ @Override
+ public double getPositionValue() {
+ mutex.verify();
+
+ if (null == this.stageRelativeTo) {
+ return super.asPositionValue(this.relativePosition, this.getParent());
+ } else {
+ return getAxialOffset();
+ }
+ }
+
/**
* Stages may be positioned relative to other stages. In that case, this will set the stage number
* against which this stage is positioned.
@@ -155,65 +242,142 @@ public class Stage extends ComponentAssembly implements FlightConfigurableCompon
* @return the stage number which this stage is positioned relative to
*/
public int getRelativeToStage() {
- return this.stageRelativeTo;
+ if (null == this.stageRelativeTo) {
+ return -1;
+ }
+
+ return this.getRocket().getChildPosition(this.stageRelativeTo);
}
+
/*
*
* @param _relTo the stage number which this stage is positioned relative to
*/
- public void setRelativeToStage(final int _relTo) {
+ public Stage setRelativeToStage(final int _relTo) {
mutex.verify();
if ((_relTo < 0) || (_relTo >= this.getRocket().getStageCount())) {
log.error("attempt to position this stage relative to a non-existent stage number. Ignoring.");
- return;
- }
- this.stageRelativeTo = _relTo;
- }
-
- public RocketComponent.Position getRelativePositionMethod() {
- return this.relativePosition;
- }
-
- public void setRelativePositionMethod(final Position position) {
- super.setRelativePosition(position);
- }
-
- public double getAxialPosition() {
- return super.getPositionValue();
- }
-
- public void setAxialPosition(final double _pos) {
- super.setPositionValue(_pos);
- if (this.outside) {
- fireComponentChangeEvent(ComponentChangeEvent.BOTH_CHANGE);
- }
- }
-
- @Override
- public int getInstanceCount() {
- return this.count;
- }
-
- @Override
- public Coordinate[] getInstanceOffsets() {
- if (this.isInline()) {
- return new Coordinate[] { new Coordinate(0, 0, 0) };
+ this.stageRelativeTo = null;
+ } else if (_relTo == this.getRocket().getChildPosition(this)) {
+ // self-referential: also an error
+ this.stageRelativeTo = null;
+ } else if (this.isCenterline()) {
+ this.relativePosition = Position.AFTER;
+ updatePrevAxialStage();
+ } else {
+ this.stageRelativeTo = (Stage) this.getRocket().getChild(_relTo);
}
- Coordinate[] toReturn = new Coordinate[this.count];
+ return this.stageRelativeTo;
+ }
+
+
+ @Override
+ public double getAxialOffset() {
+ double returnValue;
+ if (null == this.stageRelativeTo) {
+ returnValue = super.asPositionValue(Position.TOP, this.getParent());
+ } else if (this.isCenterline()) {
+ returnValue = super.asPositionValue(Position.AFTER, this.stageRelativeTo);
+ } else {
+ returnValue = super.asPositionValue(this.relativePosition, this.stageRelativeTo);
+ }
+
+ if (0.000001 > Math.abs(returnValue)) {
+ returnValue = 0.0;
+ }
+
+ return returnValue;
+ }
+
+ @Override
+ public void setAxialOffset(final double _pos) {
+ this.updateBounds();
+ super.setAxialOffset(this.relativePosition, _pos, this.stageRelativeTo);
+ fireComponentChangeEvent(ComponentChangeEvent.BOTH_CHANGE);
+ }
+
+ // TOOD: unify with 'generate instanceOffsets()'
+ // what is the use of this again?
+ @Override
+ public Coordinate[] shiftCoordinates(Coordinate[] c) {
+ checkState();
+
+ if (this.isCenterline()) {
+ return c;
+ }
+
+ if (1 < c.length) {
+ throw new BugException("implementation of 'shiftCoordinates' assumes the coordinate array has len == 1; this is not true, and may produce unexpected behavior! ");
+ }
double radius = this.radialPosition_m;
double angle0 = this.angularPosition_rad;
double angleIncr = this.angularSeparation;
-
+ Coordinate[] toReturn = new Coordinate[this.count];
+ Coordinate thisOffset;
double thisAngle = angle0;
for (int instanceNumber = 0; instanceNumber < this.count; instanceNumber++) {
- toReturn[instanceNumber] = new Coordinate(0, radius * Math.cos(thisAngle), radius * Math.sin(thisAngle));
+ thisOffset = new Coordinate(0, radius * Math.cos(thisAngle), radius * Math.sin(thisAngle));
+
+ toReturn[instanceNumber] = thisOffset.add(c[0]);
thisAngle += angleIncr;
}
return toReturn;
}
+
+ @Override
+ public void updateBounds() {
+
+ // currently only updates the length
+ this.length = 0;
+ Iterator childIterator = this.getChildren().iterator();
+ while (childIterator.hasNext()) {
+ RocketComponent curChild = childIterator.next();
+ this.length += curChild.getLength();
+ }
+
+ }
+
+ /**
+ * @Warning this will return the previous axial stage REGARDLESS of whether 'this' is in the centerline stack or not.
+ * @return previous axial stage (defined as above, in the direction of launch)
+ */
+ protected Stage updatePrevAxialStage() {
+ if (null != this.getParent()) {
+ Rocket rocket = this.getRocket();
+ int thisStageNumber = rocket.getChildPosition(this);
+ int curStageIndex = thisStageNumber - 1;
+ while (curStageIndex >= 0) {
+ Stage curStage = (Stage) rocket.getChild(curStageIndex);
+ if (curStage.isCenterline()) {
+ this.stageRelativeTo = curStage;
+ return this.stageRelativeTo;
+ }
+ curStageIndex--;
+ }
+ }
+
+ this.stageRelativeTo = null;
+ return null;
+ }
+
+ protected void updateCenter() {
+ if (null == this.stageRelativeTo) {
+ this.updatePrevAxialStage();
+ if (null == this.stageRelativeTo) {
+ // this stage is actually the topmost Stage, instead of just out-of-date
+ this.setAxialOffset(Position.ABSOLUTE, this.getLength() / 2, this.getRocket());
+ return;
+ }
+ }
+
+ // general case:
+ double offset = super.asPositionValue(this.relativePosition, this.stageRelativeTo);
+ this.setAxialOffset(this.relativePosition, offset, this.stageRelativeTo);
+ }
+
}
diff --git a/core/src/net/sf/openrocket/rocketcomponent/TubeFinSet.java b/core/src/net/sf/openrocket/rocketcomponent/TubeFinSet.java
index 9af60bff2..c34996e8f 100644
--- a/core/src/net/sf/openrocket/rocketcomponent/TubeFinSet.java
+++ b/core/src/net/sf/openrocket/rocketcomponent/TubeFinSet.java
@@ -333,7 +333,7 @@ public class TubeFinSet extends ExternalComponent {
s = this.getParent();
while (s != null) {
if (s instanceof SymmetricComponent) {
- double x = this.toRelative(new Coordinate(0, 0, 0), s)[0].x;
+ double x = this.getRelativePositionVector().x;
return ((SymmetricComponent) s).getRadius(x);
}
s = s.getParent();
diff --git a/core/test/net/sf/openrocket/rocketcomponent/StageTest.java b/core/test/net/sf/openrocket/rocketcomponent/StageTest.java
new file mode 100644
index 000000000..bc2e5805d
--- /dev/null
+++ b/core/test/net/sf/openrocket/rocketcomponent/StageTest.java
@@ -0,0 +1,627 @@
+package net.sf.openrocket.rocketcomponent;
+
+//import junit.framework.TestCase;
+import static org.hamcrest.CoreMatchers.equalTo;
+import static org.junit.Assert.assertThat;
+import net.sf.openrocket.rocketcomponent.RocketComponent.Position;
+import net.sf.openrocket.util.Coordinate;
+import net.sf.openrocket.util.BaseTestCase.BaseTestCase;
+
+import org.junit.Test;
+
+public class StageTest extends BaseTestCase {
+
+ // tolerance for compared double test results
+ protected final double EPSILON = 0.001;
+
+ protected final Coordinate ZERO = new Coordinate(0., 0., 0.);
+
+ public void test() {
+ // fail("Not yet implemented");
+ }
+
+ public Rocket createTestRocket() {
+ double tubeRadius = 1;
+ // setup
+ Rocket root = new Rocket();
+ root.setName("Rocket");
+
+ Stage sustainer = new Stage();
+ sustainer.setName("Sustainer stage");
+ RocketComponent sustainerNose = new NoseCone(Transition.Shape.CONICAL, 2.0, tubeRadius);
+ sustainerNose.setName("Sustainer Nosecone");
+ sustainer.addChild(sustainerNose);
+ RocketComponent sustainerBody = new BodyTube(3.0, tubeRadius, 0.01);
+ sustainerBody.setName("Sustainer Body ");
+ sustainer.addChild(sustainerBody);
+ root.addChild(sustainer);
+
+ Stage core = new Stage();
+ core.setName("Core stage");
+ BodyTube coreBody = new BodyTube(6.0, tubeRadius, 0.01);
+ coreBody.setName("Core Body ");
+ core.addChild(coreBody);
+ root.addChild(core);
+
+ return root;
+ }
+
+ public Stage createBooster() {
+ double tubeRadius = 0.8;
+
+ Stage booster = new Stage();
+ booster.setName("Booster Stage A");
+ booster.setOutside(true);
+ RocketComponent boosterNose = new NoseCone(Transition.Shape.CONICAL, 2.0, tubeRadius);
+ boosterNose.setName("Booster A Nosecone");
+ booster.addChild(boosterNose);
+ RocketComponent boosterBody = new BodyTube(2.0, tubeRadius, 0.01);
+ boosterBody.setName("Booster A Body ");
+ booster.addChild(boosterBody);
+ Transition boosterTail = new Transition();
+ boosterTail.setName("Booster A Tail");
+ boosterTail.setForeRadius(1.0);
+ boosterTail.setAftRadius(0.5);
+ boosterTail.setLength(1.0);
+ booster.addChild(boosterTail);
+
+ return booster;
+ }
+
+ // // instantiate a rocket with realistic numbers, matching a file that exhibited errors
+ // public Rocket createDeltaIIRocket() {
+ //
+ // // setup
+ // Rocket root = new Rocket();
+ // root.setName("Rocket");
+ //
+ // Stage payloadFairing = new Stage();
+ // root.addChild(payloadFairing);
+ // payloadFairing.setName("Payload Fairing");
+ // NoseCone payloadNose = new NoseCone(Transition.Shape.POWER, 0.0535, 0.03);
+ // payloadNose.setShapeParameter(0.55);
+ // payloadNose.setName("Payload Nosecone");
+ // payloadNose.setAftRadius(0.3);
+ // payloadNose.setThickness(0.001);
+ // payloadFairing.addChild(payloadNose);
+ // BodyTube payloadBody = new BodyTube(0.0833, 0.03, 0.001);
+ // payloadBody.setName("Payload Body ");
+ // payloadFairing.addChild(payloadBody);
+ // Transition payloadTransition = new Transition();
+ // payloadTransition.setName("Payload Aft Transition");
+ // payloadTransition.setForeRadius(0.03);
+ // payloadTransition.setAftRadius(0.024);
+ // payloadTransition.setLength(0.04);
+ // payloadFairing.addChild(payloadTransition);
+ //
+ // Stage core = new Stage();
+ // core.setName("Delta Core stage");
+ // BodyTube coreBody = new BodyTube(0.0833, 0.3, 0.001);
+ // coreBody.setName("Delta Core Body ");
+ // core.addChild(coreBody);
+ // root.addChild(core);
+ //
+ // return root;
+ // }
+
+ /* From OpenRocket Technical Documentation
+ *
+ * 3.1.4 Coordinate systems
+ * During calculation of the aerodynamic properties a coordinate system fixed to the rocket will be used.
+ * The origin of the coordinates is at the nose cone tip with the positive x-axis directed along the rocket
+ @@ -41,70 +35,302 @@ public class BodyTubeTest extends TestCase {
+ * when discussing the fins. During simulation, however, the y- and z-axes are fixed in relation to the rocket,
+ * and do not necessarily align with the plane of the pitching moments.
+ */
+
+ @Test
+ public void testSetRocketPositionFail() {
+ RocketComponent root = createTestRocket();
+ Coordinate expectedPosition;
+ Coordinate targetPosition;
+ Coordinate resultPosition;
+
+ // case 1: the Root Rocket should be stationary
+ expectedPosition = ZERO;
+ targetPosition = new Coordinate(+4.0, 0.0, 0.0);
+ root.setAxialOffset(targetPosition.x);
+ resultPosition = root.getRelativePositionVector();
+ assertThat(" Moved the rocket root itself-- this should not be enabled.", expectedPosition.x, equalTo(resultPosition.x));
+
+ }
+
+ @Test
+ public void testAddTopStage() {
+ RocketComponent root = createTestRocket();
+
+ // Sustainer Stage
+ Stage sustainer = (Stage) root.getChild(0);
+ RocketComponent sustainerNose = sustainer.getChild(0);
+ RocketComponent sustainerBody = sustainer.getChild(1);
+ assertThat(" createTestRocket failed: is sustainer stage an ancestor of the sustainer stage? ", sustainer.isAncestor(sustainer), equalTo(false));
+ assertThat(" createTestRocket failed: is sustainer stage an ancestor of the sustainer nose? ", sustainer.isAncestor(sustainerNose), equalTo(true));
+ assertThat(" createTestRocket failed: is the root rocket an ancestor of the sustainer Nose? ", root.isAncestor(sustainerNose), equalTo(true));
+ assertThat(" createTestRocket failed: is sustainer Body an ancestor of the sustainer Nose? ", sustainerBody.isAncestor(sustainerNose), equalTo(false));
+
+ double expectedSustainerLength = 5.0;
+ assertThat(" createTestRocket failed: Sustainer size: ", sustainer.getLength(), equalTo(expectedSustainerLength));
+ double expectedSustainerX = +2.5;
+ double sustainerX;
+ sustainerX = sustainer.getRelativePositionVector().x;
+ assertThat(" createTestRocket failed: Relative position: ", sustainerX, equalTo(expectedSustainerX));
+ sustainerX = sustainer.getRelativePositionVector().x;
+ assertThat(" createTestRocket failed: Absolute position: ", sustainerX, equalTo(expectedSustainerX));
+
+ double expectedSustainerNoseX = -1.5;
+ double sustainerNosePosition = sustainerNose.getRelativePositionVector().x;
+ assertThat(" createTestRocket failed: sustainer Nose X position: ", sustainerNosePosition, equalTo(expectedSustainerNoseX));
+ expectedSustainerNoseX = +1;
+ sustainerNosePosition = sustainerNose.getAbsolutePositionVector().x;
+ assertThat(" createTestRocket failed: sustainer Nose X position: ", sustainerNosePosition, equalTo(expectedSustainerNoseX));
+
+ double expectedSustainerBodyX = +1;
+ double sustainerBodyX = sustainerBody.getRelativePositionVector().x;
+ assertThat(" createTestRocket failed: sustainer body rel X position: ", sustainerBodyX, equalTo(expectedSustainerBodyX));
+ expectedSustainerBodyX = +3.5;
+ sustainerBodyX = sustainerBody.getAbsolutePositionVector().x;
+ assertThat(" createTestRocket failed: sustainer body abs X position: ", sustainerBodyX, equalTo(expectedSustainerBodyX));
+
+ }
+
+ // WARNING: this test will not pass unless 'testAddTopStage' is passing as well -- that function tests the dependencies...
+ @Test
+ public void testAddMiddleStage() {
+ RocketComponent root = createTestRocket();
+
+ // Core Stage
+ Stage core = (Stage) root.getChild(1);
+ double expectedCoreLength = 6.0;
+ assertThat(" createTestRocket failed: Core size: ", core.getLength(), equalTo(expectedCoreLength));
+ double expectedCoreX = +8.0;
+ double coreX;
+ core.setRelativePosition(Position.AFTER);
+
+ coreX = core.getRelativePositionVector().x;
+ assertThat(" createTestRocket failed: Relative position: ", coreX, equalTo(expectedCoreX));
+ coreX = core.getAbsolutePositionVector().x;
+ assertThat(" createTestRocket failed: Absolute position: ", coreX, equalTo(expectedCoreX));
+
+ RocketComponent coreBody = core.getChild(0);
+ double expectedCoreBodyX = 0.0;
+ double coreBodyX = coreBody.getRelativePositionVector().x;
+ assertThat(" createTestRocket failed: core body rel X: ", coreBodyX, equalTo(expectedCoreBodyX));
+ expectedCoreBodyX = expectedCoreX;
+ coreBodyX = coreBody.getAbsolutePositionVector().x;
+ assertThat(" createTestRocket failed: core body abs X: ", coreBodyX, equalTo(expectedCoreBodyX));
+
+ }
+
+ @Test
+ public void testSetStagePosition_topOfStack() {
+ // setup
+ RocketComponent root = createTestRocket();
+ Stage sustainer = (Stage) root.getChild(0);
+ Coordinate expectedPosition = new Coordinate(+2.5, 0., 0.); // i.e. half the tube length
+ Coordinate targetPosition = new Coordinate(+4.0, 0., 0.);
+
+ // without making the rocket 'external' and the Stage should be restricted to AFTER positioning.
+ sustainer.setOutside(false);
+ sustainer.setRelativePositionMethod(Position.ABSOLUTE);
+ assertThat("Setting a stage's position method to anything other than AFTER flags it off-center", sustainer.getOutside(), equalTo(true));
+
+ // vv function under test
+ sustainer.setAxialOffset(targetPosition.x);
+ // ^^ function under test
+
+ Coordinate resultantRelativePosition = sustainer.getRelativePositionVector();
+ assertThat(" 'setAxialPosition(double)' failed. Relative position: ", resultantRelativePosition.x, equalTo(expectedPosition.x));
+ // for all stages, the absolute position should equal the relative, because the direct parent is the root component (i.e. the Rocket)
+ Coordinate resultantAbsolutePosition = sustainer.getAbsolutePositionVector();
+ assertThat(" 'setAxialPosition(double)' failed. Absolute position: ", resultantAbsolutePosition.x, equalTo(expectedPosition.x));
+
+ }
+
+ @Test
+ public void testFindPrevAxialStage() {
+ RocketComponent root = createTestRocket();
+ Stage core = (Stage) root.getChild(1);
+ Stage booster = createBooster();
+ root.addChild(booster);
+
+ Stage booster2 = new Stage();
+ booster2.setOutside(true);
+ booster2.setName("Booster Set 2");
+ RocketComponent booster2Body = new BodyTube(2.0, 1.0, 0.01);
+ booster2Body.setName("Booster Body 2");
+ booster2.addChild(booster2Body);
+ root.addChild(booster2);
+
+ Stage booster3 = new Stage();
+ booster3.setOutside(true);
+ booster3.setName("Booster Set 3");
+ RocketComponent booster3Body = new BodyTube(4.0, 1.0, 0.01);
+ booster3Body.setName("Booster Body 3");
+ booster3.addChild(booster3Body);
+ root.addChild(booster3);
+
+ Stage tail = new Stage();
+ tail.setName("Tail");
+ RocketComponent tailBody = new BodyTube(4.0, 1.0, 0.01);
+ tailBody.setName("TailBody");
+ root.addChild(tail);
+ tail.addChild(tailBody);
+
+ Stage prevAxialStage;
+ prevAxialStage = booster3.updatePrevAxialStage();
+ assertThat(" 'setAxialPosition(double)' failed. Absolute position: ", prevAxialStage, equalTo(core));
+
+ prevAxialStage = tail.updatePrevAxialStage();
+ assertThat(" 'setAxialPosition(double)' failed. Absolute position: ", prevAxialStage, equalTo(core));
+
+ }
+
+
+ @Test
+ public void testSetStagePosition_inStack() {
+ // setup
+ RocketComponent root = createTestRocket();
+ Stage sustainer = (Stage) root.getChild(0);
+ Stage core = (Stage) root.getChild(1);
+ Coordinate expectedSustainerPosition = new Coordinate(+2.5, 0., 0.); // i.e. half the tube length
+ Coordinate expectedCorePosition = new Coordinate(+8.0, 0., 0.);
+ Coordinate targetPosition = new Coordinate(+17.0, 0., 0.);
+
+ sustainer.setAxialOffset(targetPosition.x);
+ Coordinate sustainerPosition = sustainer.getRelativePositionVector();
+ assertThat(" 'setAxialPosition(double)' failed. Relative position: ", sustainerPosition.x, equalTo(expectedSustainerPosition.x));
+
+ core.setAxialOffset(targetPosition.x);
+ Coordinate resultantCorePosition = core.getRelativePositionVector();
+ assertThat(" 'setAxialPosition(double)' failed. Absolute position: ", resultantCorePosition.x, equalTo(expectedCorePosition.x));
+
+ }
+
+ // because even though this is an "outside" stage, it's relative to itself -- i.e. an error.
+ // also an error with a well-defined failure result (i.e. just failover to AFTER placement as the first stage of a rocket.
+ @Test
+ public void testSetStagePosition_outsideABSOLUTE() {
+ // setup
+ RocketComponent root = createTestRocket();
+ Stage core = (Stage) root.getChild(1);
+ Stage booster = createBooster();
+ root.addChild(booster);
+
+ Coordinate targetPosition = new Coordinate(+17.0, 0., 0.);
+ double expectedX = targetPosition.x;
+
+ // when 'external' the stage should be freely movable
+ booster.setOutside(true);
+ booster.setRelativePositionMethod(Position.ABSOLUTE);
+ booster.setRelativeToStage(1);
+ // vv function under test
+ booster.setAxialOffset(targetPosition.x);
+ // ^^ function under test
+
+ Coordinate resultantRelativePosition = booster.getRelativePositionVector();
+ assertThat(" 'setAxialPosition(double)' failed. Relative position: ", resultantRelativePosition.x, equalTo(expectedX));
+ double resultantPositionValue = booster.getPositionValue();
+ assertThat(" 'setAxialPosition(double)' failed. PositionValue: ", resultantPositionValue, equalTo(expectedX));
+ double resultantAxialPosition = booster.getAxialOffset();
+ assertThat(" 'setAxialPosition(double)' failed. Relative position: ", resultantAxialPosition, equalTo(expectedX));
+ // for all stages, the absolute position should equal the relative, because the direct parent is the root component (i.e. the Rocket)
+ Coordinate resultantAbsolutePosition = booster.getAbsolutePositionVector();
+ assertThat(" 'setAxialPosition(double)' failed. Absolute position: ", resultantAbsolutePosition.x, equalTo(expectedX));
+ }
+
+ // WARNING:
+ // Because even though this is an "outside" stage, it's relative to itself -- i.e. an error-condition
+ // also an error with a well-defined failure result (i.e. just failover to AFTER placement as the first stage of a rocket.
+ @Test
+ public void testSetStagePosition_outsideTopOfStack() {
+ // setup
+ RocketComponent root = createTestRocket();
+ Stage sustainer = (Stage) root.getChild(0);
+ Coordinate expectedPosition = new Coordinate(+2.5, 0., 0.);
+ Coordinate targetPosition = new Coordinate(+4.0, 0., 0.);
+
+ // when 'external' the stage should be freely movable
+ sustainer.setOutside(true);
+ sustainer.setRelativePositionMethod(Position.TOP);
+ sustainer.setRelativeToStage(0);
+ int expectedRelativeIndex = -1;
+ assertThat(" 'setRelativeToStage(int)' failed. Relative stage index:", sustainer.getRelativeToStage(), equalTo(expectedRelativeIndex));
+
+ // vv function under test
+ sustainer.setAxialOffset(targetPosition.x);
+ // ^^ function under test
+
+ Coordinate resultantRelativePosition = sustainer.getRelativePositionVector();
+ assertThat(" 'setAxialPosition(double)' failed. Relative position: ", resultantRelativePosition.x, equalTo(expectedPosition.x));
+ double expectedPositionValue = 0;
+ double resultantPositionValue = sustainer.getPositionValue();
+ assertThat(" 'setPositionValue()' failed. Relative position: ", resultantPositionValue, equalTo(expectedPositionValue));
+
+ double expectedAxialPosition = 0;
+ double resultantAxialPosition = sustainer.getAxialOffset();
+ assertThat(" 'getAxialPosition()' failed. Relative position: ", resultantAxialPosition, equalTo(expectedAxialPosition));
+ // for all stages, the absolute position should equal the relative, because the direct parent is the root component (i.e. the Rocket)
+ Coordinate resultantAbsolutePosition = sustainer.getAbsolutePositionVector();
+ assertThat(" 'setAbsolutePositionVector()' failed. Absolute position: ", resultantAbsolutePosition.x, equalTo(expectedPosition.x));
+ }
+
+ @Test
+ public void testSetStagePosition_outsideTOP() {
+ Rocket root = this.createTestRocket();
+ Stage booster = createBooster();
+ root.addChild(booster);
+
+ booster.setOutside(true);
+ booster.setRelativePositionMethod(Position.TOP);
+ booster.setRelativeToStage(1);
+ // vv function under test
+ double targetOffset = +2.0;
+ booster.setAxialOffset(targetOffset);
+ // ^^ function under test
+
+ double expectedX = +9.5;
+ Coordinate resultantRelativePosition = booster.getRelativePositionVector();
+ assertThat(" 'setAxialPosition(double)' failed. Relative position: ", resultantRelativePosition.x, equalTo(expectedX));
+ // for all stages, the absolute position should equal the relative, because the direct parent is the root component (i.e. the Rocket)
+ Coordinate resultantAbsolutePosition = booster.getAbsolutePositionVector();
+ assertThat(" 'setAxialPosition(double)' failed. Absolute position: ", resultantAbsolutePosition.x, equalTo(expectedX));
+
+ double resultantAxialOffset = booster.getAxialOffset();
+ assertThat(" 'getAxialPosition()' failed. Relative position: ", resultantAxialOffset, equalTo(targetOffset));
+
+ double resultantPositionValue = booster.getPositionValue();
+ assertThat(" 'setPositionValue()' failed. Relative position: ", resultantPositionValue, equalTo(targetOffset));
+ }
+
+ @Test
+ public void testSetStagePosition_outsideMIDDLE() {
+ // setup
+ RocketComponent root = createTestRocket();
+ Stage booster = createBooster();
+ root.addChild(booster);
+
+ // when 'external' the stage should be freely movable
+ booster.setOutside(true);
+ booster.setRelativePositionMethod(Position.MIDDLE);
+ booster.setRelativeToStage(1);
+ // vv function under test
+ double targetOffset = +2.0;
+ booster.setAxialOffset(targetOffset);
+ // ^^ function under test
+
+ double expectedX = +10.0;
+ Coordinate resultantRelativePosition = booster.getRelativePositionVector();
+ assertThat(" 'setAxialPosition(double)' failed. Relative position: ", resultantRelativePosition.x, equalTo(expectedX));
+ // for all stages, the absolute position should equal the relative, because the direct parent is the root component (i.e. the Rocket)
+ Coordinate resultantAbsolutePosition = booster.getAbsolutePositionVector();
+ assertThat(" 'setAxialPosition(double)' failed. Absolute position: ", resultantAbsolutePosition.x, equalTo(expectedX));
+
+
+ double resultantPositionValue = booster.getPositionValue();
+ assertThat(" 'setPositionValue()' failed. Relative position: ", resultantPositionValue, equalTo(targetOffset));
+
+ double resultantAxialOffset = booster.getAxialOffset();
+ assertThat(" 'getAxialPosition()' failed. Relative position: ", resultantAxialOffset, equalTo(targetOffset));
+ }
+
+ @Test
+ public void testSetStagePosition_outsideBOTTOM() {
+ // setup
+ RocketComponent root = createTestRocket();
+ Stage booster = createBooster();
+ root.addChild(booster);
+
+
+ // when 'external' the stage should be freely movable
+ booster.setOutside(true);
+ booster.setRelativePositionMethod(Position.BOTTOM);
+ booster.setRelativeToStage(1);
+ // vv function under test
+ double targetOffset = +4.0;
+ booster.setAxialOffset(targetOffset);
+ // ^^ function under test
+
+ double expectedX = +12.5;
+ Coordinate resultantRelativePosition = booster.getRelativePositionVector();
+ assertThat(" 'setAxialPosition(double)' failed. Relative position: ", resultantRelativePosition.x, equalTo(expectedX));
+ // for all stages, the absolute position should equal the relative, because the direct parent is the root component (i.e. the Rocket)
+ Coordinate resultantAbsolutePosition = booster.getAbsolutePositionVector();
+ assertThat(" 'setAxialPosition(double)' failed. Absolute position: ", resultantAbsolutePosition.x, equalTo(expectedX));
+
+ double resultantPositionValue = booster.getPositionValue();
+ assertThat(" 'setPositionValue()' failed. Relative position: ", resultantPositionValue, equalTo(targetOffset));
+
+ double resultantAxialOffset = booster.getAxialOffset();
+ assertThat(" 'getAxialPosition()' failed. Relative position: ", resultantAxialOffset, equalTo(targetOffset));
+ }
+
+ @Test
+ public void testAxial_setTOP_getABSOLUTE() {
+ // setup
+ RocketComponent root = createTestRocket();
+ Stage core = (Stage) root.getChild(1);
+ Stage booster = createBooster();
+ root.addChild(booster);
+
+ double targetOffset = +4.50;
+ booster.setOutside(true);
+ booster.setRelativePositionMethod(Position.TOP);
+ booster.setRelativeToStage(1);
+ booster.setAxialOffset(targetOffset);
+
+ double expectedAxialOffset = +12.0;
+ Coordinate resultantRelativePosition = booster.getRelativePositionVector();
+ assertThat(" 'setAxialPosition(double)' failed. Relative position: ", resultantRelativePosition.x, equalTo(expectedAxialOffset));
+
+ Stage refStage = core;
+ // vv function under test
+ double resultantAxialPosition = booster.asPositionValue(Position.ABSOLUTE, refStage);
+ // ^^ function under test
+
+ assertThat(" 'setPositionValue()' failed. Relative position: ", resultantAxialPosition, equalTo(expectedAxialOffset));
+ }
+
+ @Test
+ public void testAxial_setTOP_getAFTER() {
+ // setup
+ RocketComponent root = createTestRocket();
+ Stage core = (Stage) root.getChild(1);
+ Stage booster = createBooster();
+ root.addChild(booster);
+
+ double targetOffset = +4.50;
+ booster.setOutside(true);
+ booster.setRelativePositionMethod(Position.TOP);
+ booster.setRelativeToStage(1);
+ booster.setAxialOffset(targetOffset);
+
+ Coordinate expectedPosition = new Coordinate(+12.0, 0., 0.);
+ Coordinate resultantRelativePosition = booster.getRelativePositionVector();
+ assertThat(" 'setAxialPosition(double)' failed. Relative position: ", resultantRelativePosition.x, equalTo(expectedPosition.x));
+
+ Stage refStage = core;
+ double resultantAxialPosition;
+ double expectedAxialPosition;
+ // vv function under test
+ resultantAxialPosition = booster.asPositionValue(Position.AFTER, refStage);
+ // ^^ function under test
+ expectedAxialPosition = -1.5;
+ assertThat(" 'setPositionValue()' failed. Relative position: ", resultantAxialPosition, equalTo(expectedAxialPosition));
+ }
+
+ @Test
+ public void testAxial_setTOP_getMIDDLE() {
+ // setup
+ RocketComponent root = createTestRocket();
+ Stage core = (Stage) root.getChild(1);
+ Stage booster = createBooster();
+ root.addChild(booster);
+
+
+ double targetOffset = +4.50;
+ booster.setOutside(true);
+ booster.setRelativePositionMethod(Position.TOP);
+ booster.setRelativeToStage(1);
+ booster.setAxialOffset(targetOffset);
+
+ Coordinate expectedPosition = new Coordinate(+12.0, 0., 0.);
+ Coordinate resultantRelativePosition = booster.getRelativePositionVector();
+ assertThat(" 'setAxialPosition(double)' failed. Relative position: ", resultantRelativePosition.x, equalTo(expectedPosition.x));
+
+ Stage refStage = core;
+ double resultantAxialPosition;
+ double expectedAxialPosition = +4.0;
+
+ // vv function under test
+ resultantAxialPosition = booster.asPositionValue(Position.MIDDLE, refStage);
+ // ^^ function under test
+ assertThat(" 'setPositionValue()' failed. Relative position: ", resultantAxialPosition, equalTo(expectedAxialPosition));
+ }
+
+ @Test
+ public void testAxial_setTOP_getBOTTOM() {
+ // setup
+ RocketComponent root = createTestRocket();
+ Stage core = (Stage) root.getChild(1);
+ Stage booster = createBooster();
+ root.addChild(booster);
+
+
+ double targetOffset = +4.50;
+ booster.setOutside(true);
+ booster.setRelativePositionMethod(Position.TOP);
+ booster.setRelativeToStage(1);
+ booster.setAxialOffset(targetOffset);
+
+ Coordinate expectedPosition = new Coordinate(+12.0, 0., 0.);
+ Coordinate resultantRelativePosition = booster.getRelativePositionVector();
+ assertThat(" 'setAxialPosition(double)' failed. Relative position: ", resultantRelativePosition.x, equalTo(expectedPosition.x));
+
+ Stage refStage = core;
+ double resultantAxialPosition;
+ double expectedAxialPosition;
+ // vv function under test
+ resultantAxialPosition = booster.asPositionValue(Position.BOTTOM, refStage);
+ // ^^ function under test
+ expectedAxialPosition = +3.5;
+ assertThat(" 'setPositionValue()' failed. Relative position: ", resultantAxialPosition, equalTo(expectedAxialPosition));
+ }
+
+
+ @Test
+ public void testAxial_setBOTTOM_getTOP() {
+ // setup
+ RocketComponent root = createTestRocket();
+ Stage core = (Stage) root.getChild(1);
+ Stage booster = createBooster();
+ root.addChild(booster);
+
+
+ double targetOffset = +4.50;
+ booster.setOutside(true);
+ booster.setRelativePositionMethod(Position.BOTTOM);
+ booster.setRelativeToStage(1);
+ booster.setAxialOffset(targetOffset);
+
+ Coordinate expectedPosition = new Coordinate(+13.0, 0., 0.);
+ Coordinate resultantRelativePosition = booster.getRelativePositionVector();
+ assertThat(" 'setAxialPosition(double)' failed. Relative position: ", resultantRelativePosition.x, equalTo(expectedPosition.x));
+
+ Stage refStage = core;
+ double resultantAxialPosition;
+ double expectedAxialPosition;
+
+ // vv function under test
+ resultantAxialPosition = booster.asPositionValue(Position.TOP, refStage);
+ // ^^ function under test
+ expectedAxialPosition = 5.5;
+ assertThat(" 'setPositionValue()' failed. Relative position: ", resultantAxialPosition, equalTo(expectedAxialPosition));
+ }
+
+ @Test
+ public void testInitializationOrder() {
+ Rocket root = createTestRocket();
+ Stage boosterA = createBooster();
+ root.addChild(boosterA);
+ Stage boosterB = createBooster();
+ root.addChild(boosterB);
+
+ double targetOffset = +4.50;
+
+ // requirement: regardless of initialization order (which we cannot control)
+ // two boosters with identical initialization commands should end up at the same place.
+
+ boosterA.setOutside(true);
+ boosterA.setRelativePositionMethod(Position.BOTTOM);
+ boosterA.setRelativeToStage(1);
+ boosterA.setAxialOffset(targetOffset);
+
+ boosterB.dumpDetail();
+ boosterB.setRelativePositionMethod(Position.TOP);
+ System.err.println(" B: setMeth: " + boosterB.getRelativePositionVector().x);
+ boosterB.setRelativeToStage(1);
+ System.err.println(" B: setRelTo: " + boosterB.getRelativePositionVector().x);
+ boosterB.setAxialOffset(targetOffset);
+ System.err.println(" B: setOffs: " + boosterB.getRelativePositionVector().x);
+ boosterB.setRelativePositionMethod(Position.BOTTOM);
+ System.err.println(" B: setMeth: " + boosterB.getRelativePositionVector().x);
+ boosterB.setOutside(true);
+ System.err.println(" B: setOutside:" + boosterB.getRelativePositionVector().x);
+
+ root.dumpTree(true, "");
+
+ double offsetA = boosterA.getAxialOffset();
+ double offsetB = boosterB.getAxialOffset();
+
+ assertThat(" init order error: Booster A: resultant positions: ", offsetA, equalTo(targetOffset));
+ assertThat(" init order error: Booster B: resultant positions: ", offsetB, equalTo(targetOffset));
+
+
+ }
+
+
+}
diff --git a/swing/src/net/sf/openrocket/gui/configdialog/InnerTubeConfig.java b/swing/src/net/sf/openrocket/gui/configdialog/InnerTubeConfig.java
index 614785ef4..55d2f4a1c 100644
--- a/swing/src/net/sf/openrocket/gui/configdialog/InnerTubeConfig.java
+++ b/swing/src/net/sf/openrocket/gui/configdialog/InnerTubeConfig.java
@@ -348,8 +348,8 @@ public class InnerTubeConfig extends RocketComponentConfig {
document.addUndoPosition("Split cluster");
- Coordinate[] coords = { Coordinate.NUL };
- coords = component.shiftCoordinates(coords);
+ Coordinate[] coords = new Coordinate[]{Coordinate.NUL };
+ coords = component.shiftCoordinates( coords);
parent.removeChild(index);
for (int i = 0; i < coords.length; i++) {
InnerTube copy = InnerTube.makeIndividualClusterComponent(coords[i], component.getName() + " #" + (i + 1), component);
diff --git a/swing/src/net/sf/openrocket/gui/configdialog/StageConfig.java b/swing/src/net/sf/openrocket/gui/configdialog/StageConfig.java
index 7f171ed0b..0540c6b36 100644
--- a/swing/src/net/sf/openrocket/gui/configdialog/StageConfig.java
+++ b/swing/src/net/sf/openrocket/gui/configdialog/StageConfig.java
@@ -58,21 +58,28 @@ public class StageConfig extends RocketComponentConfig {
}
private JPanel parallelTab( final Stage stage ){
- // enable parallel staging
JPanel motherPanel = new JPanel( new MigLayout("fill"));
+
+ // this stage is positioned relative to what stage?
+ JLabel relativeStageLabel = new JLabel(trans.get("Stage.parallel.componentname"));
+ motherPanel.add( relativeStageLabel);
+ ComboBoxModel relativeStageModel = new StageSelectModel( stage );
+ JComboBox relToCombo = new JComboBox( relativeStageModel );
+ motherPanel.add( relToCombo , "growx, wrap");
+
+ // enable parallel staging
+ motherPanel.add(new JSeparator(SwingConstants.HORIZONTAL), "spanx 3, growx, wrap");
BooleanModel parallelEnabledModel = new BooleanModel( component, "Outside");
parallelEnabledModel.setValue( stage.getOutside());
JCheckBox parallelEnabled = new JCheckBox( parallelEnabledModel);
- parallelEnabled.setText(trans.get("RocketCompCfg.outside.stage"));
+ parallelEnabled.setText(trans.get("Stage.parallel.toggle"));
motherPanel.add(parallelEnabled, "wrap");
- motherPanel.add(new JSeparator(SwingConstants.HORIZONTAL), "spanx 3, growx, wrap");
-
// set radial distance
- JLabel radiusLabel = new JLabel(trans.get("RocketCompCfg.outside.radius"));
+ JLabel radiusLabel = new JLabel(trans.get("Stage.parallel.radius"));
motherPanel.add( radiusLabel , "align left");
parallelEnabledModel.addEnableComponent( radiusLabel, true);
- DoubleModel radiusModel = new DoubleModel( stage, "RadialPosition", UnitGroup.UNITS_LENGTH, 0);
+ DoubleModel radiusModel = new DoubleModel( stage, "RadialOffset", UnitGroup.UNITS_LENGTH, 0);
//radiusModel.setCurrentUnit( UnitGroup.UNITS_LENGTH.getUnit("cm"));
JSpinner radiusSpinner = new JSpinner( radiusModel.getSpinnerModel());
radiusSpinner.setEditor(new SpinnerEditor(radiusSpinner ));
@@ -83,10 +90,10 @@ public class StageConfig extends RocketComponentConfig {
parallelEnabledModel.addEnableComponent( radiusUnitSelector , true);
// set location angle around the primary stage
- JLabel angleLabel = new JLabel(trans.get("RocketCompCfg.outside.angle"));
+ JLabel angleLabel = new JLabel(trans.get("Stage.parallel.angle"));
motherPanel.add( angleLabel, "align left");
parallelEnabledModel.addEnableComponent( angleLabel, true);
- DoubleModel angleModel = new DoubleModel( stage, "AngularPosition", 1.0, UnitGroup.UNITS_ANGLE, 0.0, Math.PI*2);
+ DoubleModel angleModel = new DoubleModel( stage, "AngularOffset", 1.0, UnitGroup.UNITS_ANGLE, 0.0, Math.PI*2);
angleModel.setCurrentUnit( UnitGroup.UNITS_ANGLE.getUnit("rad"));
JSpinner angleSpinner = new JSpinner(angleModel.getSpinnerModel());
angleSpinner.setEditor(new SpinnerEditor(angleSpinner));
@@ -97,11 +104,11 @@ public class StageConfig extends RocketComponentConfig {
parallelEnabledModel.addEnableComponent( angleUnitSelector , true);
// set multiplicity
- JLabel countLabel = new JLabel(trans.get("RocketCompCfg.outside.count"));
+ JLabel countLabel = new JLabel(trans.get("Stage.parallel.count"));
motherPanel.add( countLabel, "align left");
parallelEnabledModel.addEnableComponent( countLabel, true);
- IntegerModel countModel = new IntegerModel( stage, "Count", 1 );
+ IntegerModel countModel = new IntegerModel( stage, "InstanceCount", 1 );
JSpinner countSpinner = new JSpinner(countModel.getSpinnerModel());
countSpinner.setEditor(new SpinnerEditor(countSpinner));
motherPanel.add(countSpinner, "growx 1, wrap");
@@ -113,36 +120,31 @@ public class StageConfig extends RocketComponentConfig {
parallelEnabledModel.addEnableComponent( positionLabel, true);
// EnumModel(ChangeSource source, String valueName, Enum[] values) {
- ComboBoxModel posRelModel = new EnumModel(component, "RelativePositionMethod",
+ ComboBoxModel relativePositionMethodModel = new EnumModel(component, "RelativePositionMethod",
new RocketComponent.Position[] {
RocketComponent.Position.TOP,
RocketComponent.Position.MIDDLE,
RocketComponent.Position.BOTTOM,
- RocketComponent.Position.ABSOLUTE
+ RocketComponent.Position.ABSOLUTE,
+ RocketComponent.Position.AFTER
});
- JComboBox> positionMethodCombo = new JComboBox( posRelModel );
+ JComboBox> positionMethodCombo = new JComboBox( relativePositionMethodModel );
motherPanel.add(positionMethodCombo, "spanx 2, growx, wrap");
parallelEnabledModel.addEnableComponent( positionMethodCombo, true);
- // setPositions relative to parent component
- JLabel relativeStageLabel = new JLabel(trans.get("RocketCompCfg.outside.componentname"));
- motherPanel.add( relativeStageLabel);
- parallelEnabledModel.addEnableComponent( relativeStageLabel, true);
- ComboBoxModel relativeStageModel = new StageSelectModel( stage );
- JComboBox relToCombo = new JComboBox( relativeStageModel );
- motherPanel.add( relToCombo , "growx, wrap");
- parallelEnabledModel.addEnableComponent( relToCombo, true );
-
- // plus
- JLabel positionPlusLabel = new JLabel(trans.get("LaunchLugCfg.lbl.plus"));
+ // relative offset labels
+ JLabel positionPlusLabel = new JLabel(trans.get("Stage.parallel.offset"));
motherPanel.add( positionPlusLabel );
- parallelEnabledModel.addEnableComponent( positionPlusLabel, true );
-
- DoubleModel axialPositionModel = new DoubleModel(component, "AxialPosition", UnitGroup.UNITS_LENGTH);
- JSpinner axPosSpin= new JSpinner( axialPositionModel.getSpinnerModel());
+ parallelEnabledModel.addEnableComponent( positionPlusLabel, true );
+ DoubleModel axialOffsetModel = new DoubleModel(component, "AxialOffset", UnitGroup.UNITS_LENGTH);
+ axialOffsetModel.setCurrentUnit(UnitGroup.UNITS_LENGTH.getUnit("cm"));
+ JSpinner axPosSpin= new JSpinner( axialOffsetModel.getSpinnerModel());
axPosSpin.setEditor(new SpinnerEditor(axPosSpin));
motherPanel.add(axPosSpin, "growx");
parallelEnabledModel.addEnableComponent( axPosSpin, true );
+ UnitSelector axialOffsetUnitSelector = new UnitSelector(axialOffsetModel);
+ motherPanel.add(axialOffsetUnitSelector, "growx 1, wrap");
+ parallelEnabledModel.addEnableComponent( axialOffsetUnitSelector , true);
return motherPanel;
}
diff --git a/swing/src/net/sf/openrocket/gui/rocketfigure/BodyTubeShapes.java b/swing/src/net/sf/openrocket/gui/rocketfigure/BodyTubeShapes.java
index ab72c3a7b..f8e68304c 100644
--- a/swing/src/net/sf/openrocket/gui/rocketfigure/BodyTubeShapes.java
+++ b/swing/src/net/sf/openrocket/gui/rocketfigure/BodyTubeShapes.java
@@ -13,17 +13,21 @@ public class BodyTubeShapes extends RocketComponentShape {
public static RocketComponentShape[] getShapesSide(
net.sf.openrocket.rocketcomponent.RocketComponent component,
Transformation transformation,
- Coordinate instanceOffset) {
+ Coordinate componentAbsoluteLocation) {
net.sf.openrocket.rocketcomponent.BodyTube tube = (net.sf.openrocket.rocketcomponent.BodyTube)component;
double length = tube.getLength();
double radius = tube.getOuterRadius();
- Coordinate[] start = transformation.transform(tube.toAbsolute(instanceOffset));
-
- Shape[] s = new Shape[start.length];
- for (int i=0; i < start.length; i++) {
- s[i] = new Rectangle2D.Double(start[i].x*S,(start[i].y-radius)*S,
- length*S,2*radius*S);
+ Coordinate[] instanceOffsets = new Coordinate[]{ transformation.transform( componentAbsoluteLocation )};
+ instanceOffsets = component.shiftCoordinates(instanceOffsets);
+
+// System.err.println(">> Starting component "+component.getName()+" at: "+(instanceOffsets[0].x - length/2));
+ Shape[] s = new Shape[instanceOffsets.length];
+ for (int i=0; i < instanceOffsets.length; i++) {
+ s[i] = new Rectangle2D.Double((instanceOffsets[i].x-length/2)*S, //x - the X coordinate of the upper-left corner of the newly constructed Rectangle2D
+ (instanceOffsets[i].y-radius)*S, // y - the Y coordinate of the upper-left corner of the newly constructed Rectangle2D
+ length*S, // w - the width of the newly constructed Rectangle2D
+ 2*radius*S); // h - the height of the newly constructed Rectangle2D
}
return RocketComponentShape.toArray(s, component);
@@ -32,16 +36,17 @@ public class BodyTubeShapes extends RocketComponentShape {
public static RocketComponentShape[] getShapesBack(
net.sf.openrocket.rocketcomponent.RocketComponent component,
Transformation transformation,
- Coordinate instanceOffset) {
+ Coordinate componentAbsoluteLocation) {
net.sf.openrocket.rocketcomponent.BodyTube tube = (net.sf.openrocket.rocketcomponent.BodyTube)component;
double or = tube.getOuterRadius();
- Coordinate[] start = transformation.transform(tube.toAbsolute(instanceOffset));
-
- Shape[] s = new Shape[start.length];
- for (int i=0; i < start.length; i++) {
- s[i] = new Ellipse2D.Double((start[i].z-or)*S,(start[i].y-or)*S,2*or*S,2*or*S);
+ Coordinate[] instanceOffsets = new Coordinate[]{ transformation.transform( componentAbsoluteLocation )};
+ instanceOffsets = component.shiftCoordinates(instanceOffsets);
+
+ Shape[] s = new Shape[instanceOffsets.length];
+ for (int i=0; i < instanceOffsets.length; i++) {
+ s[i] = new Ellipse2D.Double((instanceOffsets[i].z-or)*S,(instanceOffsets[i].y-or)*S,2*or*S,2*or*S);
}
return RocketComponentShape.toArray(s, component);
diff --git a/swing/src/net/sf/openrocket/gui/rocketfigure/FinSetShapes.java b/swing/src/net/sf/openrocket/gui/rocketfigure/FinSetShapes.java
index 8ef726cf0..780a4675b 100644
--- a/swing/src/net/sf/openrocket/gui/rocketfigure/FinSetShapes.java
+++ b/swing/src/net/sf/openrocket/gui/rocketfigure/FinSetShapes.java
@@ -15,18 +15,19 @@ public class FinSetShapes extends RocketComponentShape {
public static RocketComponentShape[] getShapesSide(
net.sf.openrocket.rocketcomponent.RocketComponent component,
Transformation transformation,
- Coordinate instanceOffset) {
+ Coordinate componentAbsoluteLocation) {
net.sf.openrocket.rocketcomponent.FinSet finset = (net.sf.openrocket.rocketcomponent.FinSet)component;
int finCount = finset.getFinCount();
Transformation cantRotation = finset.getCantRotation();
- Transformation baseRotation = finset.getBaseRotationTransformation();
+ Transformation baseRotation = finset.getBaseRotationTransformation(); // rotation about x-axis
Transformation finRotation = finset.getFinRotationTransformation();
+ double rootChord = finset.getLength();
+ Coordinate finSetFront = componentAbsoluteLocation.sub( rootChord/2 , 0, 0);
Coordinate finPoints[] = finset.getFinPointsWithTab();
-
// TODO: MEDIUM: sloping radius
double radius = finset.getBodyRadius();
@@ -36,17 +37,20 @@ public class FinSetShapes extends RocketComponentShape {
finPoints[i] = baseRotation.transform(finPoints[i].add(0,radius,0));
}
-
+
// Generate shapes
- RocketComponentShape[] rcs = new RocketComponentShape[ finCount];
- for (int fin=0; fin= 0.0012) && (ir > 0)) {
// Draw outer and inner
- s = new Shape[start.length*2];
- for (int i=0; i < start.length; i++) {
- s[2*i] = new Rectangle2D.Double(start[i].x*S,(start[i].y-or)*S,
+ s = new Shape[instanceOffsets.length*2];
+ for (int i=0; i < instanceOffsets.length; i++) {
+ s[2*i] = new Rectangle2D.Double(instanceOffsets[i].x*S,(instanceOffsets[i].y-or)*S,
length*S,2*or*S);
- s[2*i+1] = new Rectangle2D.Double(start[i].x*S,(start[i].y-ir)*S,
+ s[2*i+1] = new Rectangle2D.Double(instanceOffsets[i].x*S,(instanceOffsets[i].y-ir)*S,
length*S,2*ir*S);
}
} else {
// Draw only outer
- s = new Shape[start.length];
- for (int i=0; i < start.length; i++) {
- s[i] = new Rectangle2D.Double(start[i].x*S,(start[i].y-or)*S,
+ s = new Shape[instanceOffsets.length];
+ for (int i=0; i < instanceOffsets.length; i++) {
+ s[i] = new Rectangle2D.Double(instanceOffsets[i].x*S,(instanceOffsets[i].y-or)*S,
length*S,2*or*S);
}
}
@@ -50,30 +50,31 @@ public class RingComponentShapes extends RocketComponentShape {
public static RocketComponentShape[] getShapesBack(
net.sf.openrocket.rocketcomponent.RocketComponent component,
Transformation transformation,
- Coordinate instanceOffset) {
+ Coordinate componentAbsoluteLocation) {
net.sf.openrocket.rocketcomponent.RingComponent tube = (net.sf.openrocket.rocketcomponent.RingComponent)component;
Shape[] s;
double or = tube.getOuterRadius();
double ir = tube.getInnerRadius();
-
- Coordinate[] start = transformation.transform(tube.toAbsolute(instanceOffset));
+ Coordinate[] instanceOffsets = new Coordinate[]{ transformation.transform( componentAbsoluteLocation )};
+ instanceOffsets = component.shiftCoordinates(instanceOffsets);
+
if ((ir < or) && (ir > 0)) {
// Draw inner and outer
- s = new Shape[start.length*2];
- for (int i=0; i < start.length; i++) {
- s[2*i] = new Ellipse2D.Double((start[i].z-or)*S, (start[i].y-or)*S,
+ s = new Shape[instanceOffsets.length*2];
+ for (int i=0; i < instanceOffsets.length; i++) {
+ s[2*i] = new Ellipse2D.Double((instanceOffsets[i].z-or)*S, (instanceOffsets[i].y-or)*S,
2*or*S, 2*or*S);
- s[2*i+1] = new Ellipse2D.Double((start[i].z-ir)*S, (start[i].y-ir)*S,
+ s[2*i+1] = new Ellipse2D.Double((instanceOffsets[i].z-ir)*S, (instanceOffsets[i].y-ir)*S,
2*ir*S, 2*ir*S);
}
} else {
// Draw only outer
- s = new Shape[start.length];
- for (int i=0; i < start.length; i++) {
- s[i] = new Ellipse2D.Double((start[i].z-or)*S,(start[i].y-or)*S,2*or*S,2*or*S);
+ s = new Shape[instanceOffsets.length];
+ for (int i=0; i < instanceOffsets.length; i++) {
+ s[i] = new Ellipse2D.Double((instanceOffsets[i].z-or)*S,(instanceOffsets[i].y-or)*S,2*or*S,2*or*S);
}
}
return RocketComponentShape.toArray( s, component);
diff --git a/swing/src/net/sf/openrocket/gui/rocketfigure/ShockCordShapes.java b/swing/src/net/sf/openrocket/gui/rocketfigure/ShockCordShapes.java
index 1501bb5cd..63838d8db 100644
--- a/swing/src/net/sf/openrocket/gui/rocketfigure/ShockCordShapes.java
+++ b/swing/src/net/sf/openrocket/gui/rocketfigure/ShockCordShapes.java
@@ -14,20 +14,26 @@ public class ShockCordShapes extends RocketComponentShape {
public static RocketComponentShape[] getShapesSide(
net.sf.openrocket.rocketcomponent.RocketComponent component,
Transformation transformation,
- Coordinate instanceOffset) {
+ Coordinate componentAbsoluteLocation) {
- net.sf.openrocket.rocketcomponent.MassObject tube = (net.sf.openrocket.rocketcomponent.MassObject)component;
+ net.sf.openrocket.rocketcomponent.MassObject massObj = (net.sf.openrocket.rocketcomponent.MassObject)component;
- double length = tube.getLength();
- double radius = tube.getRadius();
+ double length = massObj.getLength();
+ double radius = massObj.getRadius();
double arc = Math.min(length, 2*radius) * 0.7;
- Coordinate[] start = transformation.transform(tube.toAbsolute(instanceOffset));
-
- Shape[] s = new Shape[start.length];
- for (int i=0; i < start.length; i++) {
- s[i] = new RoundRectangle2D.Double(start[i].x*S,(start[i].y-radius)*S,
+
+ Shape[] s = new Shape[0];
+ Coordinate start = componentAbsoluteLocation;
+ s[0] = new RoundRectangle2D.Double((start.x-radius)*S,(start.y-radius)*S,
length*S,2*radius*S,arc*S,arc*S);
- }
+
+// Coordinate[] start = transformation.transform(tube.toAbsolute(instanceOffset));
+//
+// Shape[] s = new Shape[start.length];
+// for (int i=0; i < start.length; i++) {
+// s[i] = new RoundRectangle2D.Double(start[i].x*S,(start[i].y-radius)*S,
+// length*S,2*radius*S,arc*S,arc*S);
+// }
return RocketComponentShape.toArray( addSymbol(s), component);
}
@@ -35,18 +41,22 @@ public class ShockCordShapes extends RocketComponentShape {
public static RocketComponentShape[] getShapesBack(
net.sf.openrocket.rocketcomponent.RocketComponent component,
Transformation transformation,
- Coordinate instanceOffset) {
+ Coordinate componentAbsoluteLocation) {
net.sf.openrocket.rocketcomponent.MassObject tube = (net.sf.openrocket.rocketcomponent.MassObject)component;
double or = tube.getRadius();
- Coordinate[] start = transformation.transform(tube.toAbsolute(instanceOffset));
-
- Shape[] s = new Shape[start.length];
- for (int i=0; i < start.length; i++) {
- s[i] = new Ellipse2D.Double((start[i].z-or)*S,(start[i].y-or)*S,2*or*S,2*or*S);
- }
+ Shape[] s = new Shape[0];
+ Coordinate start = componentAbsoluteLocation;
+ s[0] = new Ellipse2D.Double((start.z-or)*S,(start.y-or)*S,2*or*S,2*or*S);
+
+// Coordinate[] start = transformation.transform(tube.toAbsolute(instanceOffset));
+//
+// Shape[] s = new Shape[start.length];
+// for (int i=0; i < start.length; i++) {
+// s[i] = new Ellipse2D.Double((start[i].z-or)*S,(start[i].y-or)*S,2*or*S,2*or*S);
+// }
return RocketComponentShape.toArray( s, component);
}
diff --git a/swing/src/net/sf/openrocket/gui/rocketfigure/StreamerShapes.java b/swing/src/net/sf/openrocket/gui/rocketfigure/StreamerShapes.java
index b256d3920..c369c8d3d 100644
--- a/swing/src/net/sf/openrocket/gui/rocketfigure/StreamerShapes.java
+++ b/swing/src/net/sf/openrocket/gui/rocketfigure/StreamerShapes.java
@@ -14,20 +14,25 @@ public class StreamerShapes extends RocketComponentShape {
public static RocketComponentShape[] getShapesSide(
net.sf.openrocket.rocketcomponent.RocketComponent component,
Transformation transformation,
- Coordinate instanceOffset) {
+ Coordinate componentAbsoluteLocation ) {
- net.sf.openrocket.rocketcomponent.MassObject tube = (net.sf.openrocket.rocketcomponent.MassObject)component;
+ net.sf.openrocket.rocketcomponent.MassObject massObj = (net.sf.openrocket.rocketcomponent.MassObject)component;
- double length = tube.getLength();
- double radius = tube.getRadius();
+ double length = massObj.getLength();
+ double radius = massObj.getRadius();
double arc = Math.min(length, 2*radius) * 0.7;
- Coordinate[] start = transformation.transform(tube.toAbsolute(instanceOffset));
-
- Shape[] s = new Shape[start.length];
- for (int i=0; i < start.length; i++) {
- s[i] = new RoundRectangle2D.Double(start[i].x*S,(start[i].y-radius)*S,
+
+ Shape[] s = new Shape[0];
+ Coordinate center = componentAbsoluteLocation;
+ s[0] = new RoundRectangle2D.Double((center.x-radius)*S,(center.y-radius)*S,
length*S,2*radius*S,arc*S,arc*S);
- }
+
+// Coordinate[] start = transformation.transform(tube.toAbsolute(instanceOffset));
+// Shape[] s = new Shape[start.length];
+// for (int i=0; i < start.length; i++) {
+// s[i] = new RoundRectangle2D.Double(start[i].x*S,(start[i].y-radius)*S,
+// length*S,2*radius*S,arc*S,arc*S);
+// }
return RocketComponentShape.toArray(addSymbol(s), component);
}
@@ -35,18 +40,21 @@ public class StreamerShapes extends RocketComponentShape {
public static RocketComponentShape[] getShapesBack(
net.sf.openrocket.rocketcomponent.RocketComponent component,
Transformation transformation,
- Coordinate instanceOffset) {
+ Coordinate componentAbsoluteLocation) {
net.sf.openrocket.rocketcomponent.MassObject tube = (net.sf.openrocket.rocketcomponent.MassObject)component;
double or = tube.getRadius();
-
- Coordinate[] start = transformation.transform(tube.toAbsolute(instanceOffset));
-
- Shape[] s = new Shape[start.length];
- for (int i=0; i < start.length; i++) {
- s[i] = new Ellipse2D.Double((start[i].z-or)*S,(start[i].y-or)*S,2*or*S,2*or*S);
- }
+ Shape[] s = new Shape[0];
+ Coordinate center = componentAbsoluteLocation;
+ s[0] = new Ellipse2D.Double((center.z-or)*S,(center.y-or)*S,2*or*S,2*or*S);
+
+// Coordinate[] start = transformation.transform(tube.toAbsolute(instanceOffset));
+//
+// Shape[] s = new Shape[start.length];
+// for (int i=0; i < start.length; i++) {
+// s[i] = new Ellipse2D.Double((start[i].z-or)*S,(start[i].y-or)*S,2*or*S,2*or*S);
+// }
return RocketComponentShape.toArray(s, component);
}
diff --git a/swing/src/net/sf/openrocket/gui/rocketfigure/SymmetricComponentShapes.java b/swing/src/net/sf/openrocket/gui/rocketfigure/SymmetricComponentShapes.java
index cf41fe141..f81042587 100644
--- a/swing/src/net/sf/openrocket/gui/rocketfigure/SymmetricComponentShapes.java
+++ b/swing/src/net/sf/openrocket/gui/rocketfigure/SymmetricComponentShapes.java
@@ -4,7 +4,6 @@ import net.sf.openrocket.util.Coordinate;
import net.sf.openrocket.util.MathUtil;
import net.sf.openrocket.util.Transformation;
-import java.awt.*;
import java.awt.geom.Path2D;
import java.util.ArrayList;
@@ -20,22 +19,21 @@ public class SymmetricComponentShapes extends RocketComponentShape {
public static RocketComponentShape[] getShapesSide(
net.sf.openrocket.rocketcomponent.RocketComponent component,
Transformation transformation,
- Coordinate instanceOffset) {
+ Coordinate componentAbsoluteLocation) {
- return getShapesSide(component, transformation, instanceOffset, S);
+ return getShapesSide(component, transformation, componentAbsoluteLocation, S);
}
public static RocketComponentShape[] getShapesSide(
net.sf.openrocket.rocketcomponent.RocketComponent component,
Transformation transformation,
- Coordinate instanceOffset,
+ Coordinate componentAbsoluteLocation,
final double scaleFactor) {
net.sf.openrocket.rocketcomponent.SymmetricComponent c = (net.sf.openrocket.rocketcomponent.SymmetricComponent) component;
int i;
final double delta = 0.0000001;
double x;
-
ArrayList points = new ArrayList();
x = delta;
@@ -71,11 +69,10 @@ public class SymmetricComponentShapes extends RocketComponentShape {
//System.out.println("Final points: "+points.size());
- final int len = points.size();
- for (i = 0; i < len; i++) {
- points.set(i, c.toAbsolute(points.get(i))[0]);
- }
+// for (i = 0; i < len; i++) {
+// points.set(i, c.toAbsolute(points.get(i))[0]);
+// }
/* Show points:
Shape[] s = new Shape[len+1];
@@ -87,18 +84,20 @@ public class SymmetricComponentShapes extends RocketComponentShape {
//System.out.println("here");
- Coordinate center = instanceOffset;
+ final int len = points.size();
+ Coordinate center = componentAbsoluteLocation;
+ Coordinate nose = center.sub( component.getLength()/2, 0, 0);
// TODO: LOW: curved path instead of linear
Path2D.Double path = new Path2D.Double();
- path.moveTo(points.get(len - 1).x * scaleFactor, (center.y+points.get(len - 1).y) * scaleFactor);
+ path.moveTo((nose.x + points.get(len - 1).x) * scaleFactor, (center.y+points.get(len - 1).y) * scaleFactor);
for (i = len - 2; i >= 0; i--) {
- path.lineTo(points.get(i).x * scaleFactor, (center.y+points.get(i).y) * scaleFactor);
+ path.lineTo((nose.x+points.get(i).x)* scaleFactor, (center.y+points.get(i).y) * scaleFactor);
}
for (i = 0; i < len; i++) {
- path.lineTo(points.get(i).x * scaleFactor, (center.y-points.get(i).y) * scaleFactor);
+ path.lineTo((nose.x+points.get(i).x) * scaleFactor, (center.y-points.get(i).y) * scaleFactor);
}
- path.lineTo(points.get(len - 1).x * scaleFactor, (center.y+points.get(len - 1).y) * scaleFactor);
+ path.lineTo((nose.x+points.get(len - 1).x) * scaleFactor, (center.y+points.get(len - 1).y) * scaleFactor);
path.closePath();
//s[len] = path;
diff --git a/swing/src/net/sf/openrocket/gui/rocketfigure/TransitionShapes.java b/swing/src/net/sf/openrocket/gui/rocketfigure/TransitionShapes.java
index 25e3dba88..68d4869fb 100644
--- a/swing/src/net/sf/openrocket/gui/rocketfigure/TransitionShapes.java
+++ b/swing/src/net/sf/openrocket/gui/rocketfigure/TransitionShapes.java
@@ -1,6 +1,5 @@
package net.sf.openrocket.gui.rocketfigure;
-import net.sf.openrocket.gui.scalefigure.RocketFigure;
import net.sf.openrocket.rocketcomponent.Transition;
import net.sf.openrocket.util.Coordinate;
import net.sf.openrocket.util.Transformation;
@@ -8,7 +7,6 @@ import net.sf.openrocket.util.Transformation;
import java.awt.*;
import java.awt.geom.Ellipse2D;
import java.awt.geom.Path2D;
-import java.awt.geom.Point2D;
import java.awt.geom.Rectangle2D;
@@ -26,53 +24,55 @@ public class TransitionShapes extends RocketComponentShape {
public static RocketComponentShape[] getShapesSide(
net.sf.openrocket.rocketcomponent.RocketComponent component,
Transformation transformation,
- Coordinate instanceOffset,
+ Coordinate componentAbsoluteLocation,
final double scaleFactor) {
net.sf.openrocket.rocketcomponent.Transition transition = (net.sf.openrocket.rocketcomponent.Transition)component;
RocketComponentShape[] mainShapes;
+ Coordinate center = transformation.transform( componentAbsoluteLocation );
+ // this component type does not allow multiple instances
+
// Simpler shape for conical transition, others use the method from SymmetricComponent
if (transition.getType() == Transition.Shape.CONICAL) {
- double length = transition.getLength();
+ double halflength = transition.getLength()/2;
double r1 = transition.getForeRadius();
double r2 = transition.getAftRadius();
- Coordinate start = transformation.transform(transition.
- toAbsolute(instanceOffset)[0]);
Path2D.Float path = new Path2D.Float();
- path.moveTo( start.x* scaleFactor, (start.y+ r1)* scaleFactor);
- path.lineTo( (start.x+length)* scaleFactor, (start.y+r2)* scaleFactor);
- path.lineTo( (start.x+length)* scaleFactor, (start.y-r2)* scaleFactor);
- path.lineTo( start.x* scaleFactor, (start.y-r1)* scaleFactor);
+ path.moveTo( (center.x-halflength)* scaleFactor, (center.y+ r1)* scaleFactor);
+ path.lineTo( (center.x+halflength)* scaleFactor, (center.y+r2)* scaleFactor);
+ path.lineTo( (center.x+halflength)* scaleFactor, (center.y-r2)* scaleFactor);
+ path.lineTo( (center.x-halflength)* scaleFactor, (center.y-r1)* scaleFactor);
path.closePath();
mainShapes = new RocketComponentShape[] { new RocketComponentShape( path, component) };
} else {
- mainShapes = SymmetricComponentShapes.getShapesSide(component, transformation, instanceOffset, scaleFactor);
+ mainShapes = SymmetricComponentShapes.getShapesSide(component, transformation, componentAbsoluteLocation, scaleFactor);
}
- Rectangle2D.Double shoulder1=null, shoulder2=null;
+ Rectangle2D.Double foreShoulder=null, aftShoulder=null;
int arrayLength = mainShapes.length;
if (transition.getForeShoulderLength() > 0.0005) {
- Coordinate start = transformation.transform(transition.
- toAbsolute(instanceOffset)[0]);
- double r = transition.getForeShoulderRadius();
- double l = transition.getForeShoulderLength();
- shoulder1 = new Rectangle2D.Double((start.x-l)* scaleFactor, (start.y-r)* scaleFactor, l* scaleFactor, 2*r* scaleFactor);
+ Coordinate foreTransitionShoulderCenter = componentAbsoluteLocation.sub( (transition.getLength() + transition.getForeShoulderLength())/2, 0, 0);
+ center = transformation.transform( foreTransitionShoulderCenter);
+
+ double rad = transition.getForeShoulderRadius();
+ double len = transition.getForeShoulderLength();
+ foreShoulder = new Rectangle2D.Double((center.x-len/2)* scaleFactor, (center.y-rad)* scaleFactor, len* scaleFactor, 2*rad* scaleFactor);
arrayLength++;
}
if (transition.getAftShoulderLength() > 0.0005) {
- Coordinate start = transformation.transform(transition.
- toAbsolute(instanceOffset.add(transition.getLength(),0, 0))[0]);
-
- double r = transition.getAftShoulderRadius();
- double l = transition.getAftShoulderLength();
- shoulder2 = new Rectangle2D.Double(start.x* scaleFactor, (start.y-r)* scaleFactor, l* scaleFactor, 2*r* scaleFactor);
+ Coordinate aftTransitionShoulderCenter = componentAbsoluteLocation.add( (transition.getLength() + transition.getAftShoulderLength())/2, 0, 0);
+ center= transformation.transform( aftTransitionShoulderCenter );
+
+ double rad = transition.getAftShoulderRadius();
+ double len = transition.getAftShoulderLength();
+ aftShoulder = new Rectangle2D.Double((center.x-len/2)* scaleFactor, (center.y-rad)* scaleFactor, len* scaleFactor, 2*rad* scaleFactor);
arrayLength++;
}
- if (shoulder1==null && shoulder2==null)
+ if (foreShoulder==null && aftShoulder==null)
return mainShapes;
Shape[] shapes = new Shape[arrayLength];
@@ -81,12 +81,12 @@ public class TransitionShapes extends RocketComponentShape {
for (i=0; i < mainShapes.length; i++) {
shapes[i] = mainShapes[i].shape;
}
- if (shoulder1 != null) {
- shapes[i] = shoulder1;
+ if (foreShoulder != null) {
+ shapes[i] = foreShoulder;
i++;
}
- if (shoulder2 != null) {
- shapes[i] = shoulder2;
+ if (aftShoulder != null) {
+ shapes[i] = aftShoulder;
}
return RocketComponentShape.toArray( shapes, component);
}
@@ -95,14 +95,14 @@ public class TransitionShapes extends RocketComponentShape {
public static RocketComponentShape[] getShapesBack(
net.sf.openrocket.rocketcomponent.RocketComponent component,
Transformation transformation,
- Coordinate instanceOffset) {
+ Coordinate componentAbsoluteLocation) {
net.sf.openrocket.rocketcomponent.Transition transition = (net.sf.openrocket.rocketcomponent.Transition)component;
double r1 = transition.getForeRadius();
double r2 = transition.getAftRadius();
- Coordinate center = instanceOffset;
+ Coordinate center = componentAbsoluteLocation;
Shape[] s = new Shape[2];
s[0] = new Ellipse2D.Double((center.z-r1)*S,(center.y-r1)*S,2*r1*S,2*r1*S);
diff --git a/swing/src/net/sf/openrocket/gui/rocketfigure/TubeFinSetShapes.java b/swing/src/net/sf/openrocket/gui/rocketfigure/TubeFinSetShapes.java
index 56f9fe356..c34733435 100644
--- a/swing/src/net/sf/openrocket/gui/rocketfigure/TubeFinSetShapes.java
+++ b/swing/src/net/sf/openrocket/gui/rocketfigure/TubeFinSetShapes.java
@@ -13,30 +13,31 @@ public class TubeFinSetShapes extends RocketComponentShape {
public static RocketComponentShape[] getShapesSide(
net.sf.openrocket.rocketcomponent.RocketComponent component,
Transformation transformation,
- Coordinate instanceOffset) {
+ Coordinate componentAbsoluteLocation) {
net.sf.openrocket.rocketcomponent.TubeFinSet finset = (net.sf.openrocket.rocketcomponent.TubeFinSet)component;
int fins = finset.getFinCount();
double length = finset.getLength();
- double outerradius = finset.getOuterRadius();
- double bodyradius = finset.getBodyRadius();
+ double outerRadius = finset.getOuterRadius();
+ double bodyRadius = finset.getBodyRadius();
- Coordinate[] start = finset.toAbsolute(instanceOffset);
+ Coordinate[] start = new Coordinate[]{ transformation.transform( componentAbsoluteLocation.sub( length/2, 0, 0) )};
+ start = component.shiftCoordinates( start);
Transformation baseRotation = finset.getBaseRotationTransformation();
Transformation finRotation = finset.getFinRotationTransformation();
// Translate & rotate the coordinates
for (int i=0; i childrenToReplicate = new ArrayList();
- for ( int instanceNumber = 0; instanceNumber < instanceCount; instanceNumber++ ){
- childrenToReplicate.clear();
- Coordinate curInstanceOffset = componentLocation.add( instanceOffsets[instanceNumber] );
-
- // get n children shapes toReplicate
- for ( int childNumber = 0; childNumber < childCount; childNumber++ ){
- RocketComponent curChildComp = comp.getChild( childNumber);
- getShapeTree( childrenToReplicate, curChildComp, curInstanceOffset);
- }
-
- for ( RocketComponentShape curShape : childrenToReplicate ){
- allShapes.add( curShape);
- }
-
- }
+ //System.err.println(">> Drawing component "+comp.getName()+" at relloc: "+componentAbsoluteLocation);
+ if( ( comp instanceof Rocket)||( comp instanceof Stage )){
+ // these components don't have any shapes to generate / get
+ // No-Op
}else{
- if( comp instanceof Rocket){
- // the Rocket doesn't have any graphics to get.
- // Noop
- }else{
- // for most RocketComponents
- // TODO: HIGH: TEST that getThisShape will actually relocate by the given offset
- RocketComponentShape[] childShapes = getThisShape( viewType, comp, parentOffset, viewTransform);
-
- for ( RocketComponentShape curShape : childShapes ){
- allShapes.add( curShape );
- }
+// if( comp instanceof FinSet ){
+// System.err.println(">> Drawing component "+comp.getName()+" at absloc: "+componentAbsoluteLocation);
+// System.err.println(" (parent was at: "+parentOffset);
+// }
+ RocketComponentShape[] childShapes = getThisShape( viewType, comp, componentAbsoluteLocation, viewTransform);
+
+ for ( RocketComponentShape curShape : childShapes ){
+ allShapes.add( curShape );
}
-
- // recurse to each child
- for( RocketComponent child: comp.getChildren() ){
- getShapeTree( allShapes, child, parentOffset);
- }
}
+
+ // recurse to each child
+ for( RocketComponent child: comp.getChildren() ){
+ getShapeTree( allShapes, child, componentAbsoluteLocation);
+ }
return;
}