fixed many display issues relating to refactoring of RocketComponent axialOffset code.
This commit is contained in:
parent
3b1de9c291
commit
2f42594acb
@ -825,12 +825,6 @@ RocketCompCfg.tab.Override = Override
|
||||
RocketCompCfg.tab.MassandCGoverride = Mass and CG override options
|
||||
RocketCompCfg.tab.Parallel = Parallel
|
||||
RocketCompCfg.tab.ParallelComment = Options for locating stages parallel to other stages
|
||||
RocketCompCfg.outside.stage = Make this Stage Parallel
|
||||
RocketCompCfg.outside.radius = Radial Distance
|
||||
RocketCompCfg.outside.angle = Angle
|
||||
RocketCompCfg.outside.count = Number of Boosters
|
||||
RocketCompCfg.outside.rotation = Rotation
|
||||
RocketCompCfg.outside.componentname = Name of parent component
|
||||
RocketCompCfg.tab.Figure = Figure
|
||||
RocketCompCfg.tab.Figstyleopt = Figure style options
|
||||
RocketCompCfg.tab.Comment = Comment
|
||||
@ -1388,6 +1382,14 @@ Stage.SeparationEvent.EJECTION = Current stage ejection charge
|
||||
Stage.SeparationEvent.LAUNCH = Launch
|
||||
Stage.SeparationEvent.NEVER = Never
|
||||
|
||||
Stage.parallel.toggle = Make this Stage Parallel
|
||||
Stage.parallel.radius = Radial Distance
|
||||
Stage.parallel.angle = Angle
|
||||
Stage.parallel.count = Number of Boosters
|
||||
Stage.parallel.rotation = Rotation
|
||||
Stage.parallel.componentname = Relative to Stage
|
||||
Stage.parallel.offset = Offset Value
|
||||
|
||||
! BodyTube
|
||||
BodyTube.BodyTube = Body tube
|
||||
! TubeCoupler
|
||||
|
@ -400,7 +400,7 @@ public class FinSetCalc extends RocketComponentCalc {
|
||||
double y = i * dy;
|
||||
|
||||
macLength += length * length;
|
||||
logger.debug("macLength = {}, length = {}, i = {}", macLength, length, i);
|
||||
//logger.debug("macLength = {}, length = {}, i = {}", macLength, length, i);
|
||||
macSpan += y * length;
|
||||
macLead += chordLead[i] * length;
|
||||
area += length;
|
||||
@ -416,7 +416,7 @@ public class FinSetCalc extends RocketComponentCalc {
|
||||
}
|
||||
|
||||
macLength *= dy;
|
||||
logger.debug("macLength = {}", macLength);
|
||||
//logger.debug("macLength = {}", macLength);
|
||||
macSpan *= dy;
|
||||
macLead *= dy;
|
||||
area *= dy;
|
||||
|
@ -408,9 +408,9 @@ class DocumentConfig {
|
||||
Reflection.findMethod(StageSeparationConfiguration.class, "setSeparationDelay", double.class)));
|
||||
setters.put("Stage:outside", new BooleanSetter(Reflection.findMethod(Stage.class, "setOutside", boolean.class)));
|
||||
setters.put("Stage:relativeto", new IntSetter(Reflection.findMethod(Stage.class, "setRelativeToStage", int.class)));
|
||||
setters.put("Stage:instancecount", new IntSetter(Reflection.findMethod(Stage.class, "setCount", int.class)));
|
||||
setters.put("Stage:radialoffset", new DoubleSetter(Reflection.findMethod(Stage.class, "setRadialPosition", double.class)));
|
||||
setters.put("Stage:angleoffset", new DoubleSetter(Reflection.findMethod(Stage.class, "setAngularPosition", double.class)));
|
||||
setters.put("Stage:instancecount", new IntSetter(Reflection.findMethod(Stage.class, "setInstanceCount", int.class)));
|
||||
setters.put("Stage:radialoffset", new DoubleSetter(Reflection.findMethod(Stage.class, "setRadialOffset", double.class)));
|
||||
setters.put("Stage:angleoffset", new DoubleSetter(Reflection.findMethod(Stage.class, "setAngularOffset", double.class)));
|
||||
|
||||
}
|
||||
|
||||
|
@ -35,19 +35,19 @@ class PositionSetter implements Setter {
|
||||
|
||||
if (c instanceof FinSet) {
|
||||
((FinSet) c).setRelativePosition(type);
|
||||
c.setPositionValue(pos);
|
||||
c.setAxialOffset(pos);
|
||||
} else if (c instanceof LaunchLug) {
|
||||
((LaunchLug) c).setRelativePosition(type);
|
||||
c.setPositionValue(pos);
|
||||
c.setAxialOffset(pos);
|
||||
} else if (c instanceof InternalComponent) {
|
||||
((InternalComponent) c).setRelativePosition(type);
|
||||
c.setPositionValue(pos);
|
||||
c.setAxialOffset(pos);
|
||||
} else if (c instanceof TubeFinSet) {
|
||||
((TubeFinSet) c).setRelativePosition(type);
|
||||
c.setPositionValue(pos);
|
||||
c.setAxialOffset(pos);
|
||||
} else if (c instanceof Stage) {
|
||||
((Stage) c).setRelativePositionMethod(type);
|
||||
((Stage) c).setPositionValue(pos);
|
||||
c.setAxialOffset(pos);
|
||||
} else {
|
||||
warnings.add(Warning.FILE_INVALID_PARAMETER);
|
||||
}
|
||||
|
@ -83,7 +83,7 @@ public class RocketComponentSaver {
|
||||
if (c.getRelativePosition() != RocketComponent.Position.AFTER) {
|
||||
// The type names are currently equivalent to the enum names except for case.
|
||||
String type = c.getRelativePosition().name().toLowerCase(Locale.ENGLISH);
|
||||
elements.add("<position type=\"" + type + "\">" + c.getPositionValue() + "</position>");
|
||||
elements.add("<position type=\"" + type + "\">" + c.getAxialOffset() + "</position>");
|
||||
}
|
||||
|
||||
|
||||
|
@ -84,9 +84,9 @@ public class StageSaver extends ComponentAssemblySaver {
|
||||
elementsToReturn.add("<" + outside_tag + ">" + outsideFlag + "</" + outside_tag + ">");
|
||||
int instanceCount = currentStage.getInstanceCount();
|
||||
elementsToReturn.add("<" + instCt_tag + ">" + instanceCount + "</" + instCt_tag + ">");
|
||||
double radialOffset = currentStage.getRadialPosition();
|
||||
double radialOffset = currentStage.getRadialOffset();
|
||||
elementsToReturn.add("<" + radoffs_tag + ">" + radialOffset + "</" + radoffs_tag + ">");
|
||||
double angularOffset = currentStage.getAngularPosition();
|
||||
double angularOffset = currentStage.getAngularOffset();
|
||||
elementsToReturn.add("<" + startangle_tag + ">" + angularOffset + "</" + startangle_tag + ">");
|
||||
|
||||
}
|
||||
|
@ -1,24 +0,0 @@
|
||||
package net.sf.openrocket.rocketcomponent;
|
||||
|
||||
import net.sf.openrocket.util.Coordinate;
|
||||
|
||||
|
||||
/**
|
||||
* This interface is used to signal that the implementing interface contains multiple instances of its components.
|
||||
* (Note: not all implementations replicate their children, but that is design intention.)
|
||||
*
|
||||
* @author teyrana ( Daniel Williams, equipoise@gmail.com )
|
||||
*
|
||||
*/
|
||||
|
||||
public interface MultipleComponent {
|
||||
|
||||
|
||||
public int getInstanceCount();
|
||||
|
||||
// location of each instance relative to the component
|
||||
// center-to-center vectors
|
||||
public Coordinate[] getInstanceOffsets();
|
||||
|
||||
|
||||
}
|
@ -23,28 +23,28 @@ public interface OutsideComponent {
|
||||
*
|
||||
* @return Angular position in radians.
|
||||
*/
|
||||
public double getAngularPosition();
|
||||
public double getAngularOffset();
|
||||
|
||||
/**
|
||||
* Set the position of this component in polar coordinates
|
||||
*
|
||||
* @param phi Angular position in radians
|
||||
*/
|
||||
public void setAngularPosition(final double phi);
|
||||
public void setAngularOffset(final double phi);
|
||||
|
||||
/**
|
||||
* Number of instances this stage represents
|
||||
*
|
||||
* @return number of instances this stage currently represents
|
||||
*/
|
||||
public int getCount();
|
||||
public int getInstanceCount();
|
||||
|
||||
/**
|
||||
* Set the multiplicity of this component
|
||||
*
|
||||
* @param number of instances this component should represent
|
||||
*/
|
||||
public void setCount(final int phi);
|
||||
public void setInstanceCount(final int phi);
|
||||
|
||||
|
||||
/**
|
||||
@ -52,13 +52,13 @@ public interface OutsideComponent {
|
||||
*
|
||||
* @return Radial position in radians (m)
|
||||
*/
|
||||
public double getRadialPosition();
|
||||
public double getRadialOffset();
|
||||
|
||||
/**
|
||||
* Get the position of this component in polar coordinates
|
||||
*
|
||||
* @param radius Radial distance in standard units. (m)
|
||||
*/
|
||||
public void setRadialPosition(final double radius);
|
||||
public void setRadialOffset(final double radius);
|
||||
|
||||
}
|
||||
|
@ -391,8 +391,6 @@ public class Rocket extends RocketComponent {
|
||||
return;
|
||||
}
|
||||
|
||||
log.debug("Firing rocket change event " + e);
|
||||
|
||||
// Notify all components first
|
||||
Iterator<RocketComponent> iterator = this.iterator(true);
|
||||
while (iterator.hasNext()) {
|
||||
@ -636,8 +634,6 @@ public class Rocket extends RocketComponent {
|
||||
|
||||
|
||||
//////// Obligatory component information
|
||||
|
||||
|
||||
@Override
|
||||
public String getComponentName() {
|
||||
//// Rocket
|
||||
|
@ -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 <code>position</code>
|
||||
*/
|
||||
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.
|
||||
* <p>
|
||||
* 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 <code>c</code> 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 <code>c</code> described in the coordinate system of
|
||||
* <code>dest</code>. If <code>dest</code> is <code>null</code> returns
|
||||
@ -1006,16 +1090,24 @@ public abstract class RocketComponent implements ChangeSource, Cloneable, Iterab
|
||||
* <p>
|
||||
* 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 <code>c</code> in coordinates
|
||||
* relative to <code>dest</code>.
|
||||
*/
|
||||
@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> R accept(RocketComponentVisitor<R> 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<RocketComponent> iterator = this.children.iterator();
|
||||
while (iterator.hasNext()) {
|
||||
iterator.next().dumpTree(false, prefix + " ");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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<StageSeparationConfiguration>(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<StageSeparationConfiguration> 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<RocketComponent> 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);
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -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();
|
||||
|
627
core/test/net/sf/openrocket/rocketcomponent/StageTest.java
Normal file
627
core/test/net/sf/openrocket/rocketcomponent/StageTest.java
Normal file
@ -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));
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
}
|
@ -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);
|
||||
|
@ -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<Stage> relativeStageModel = new StageSelectModel( stage );
|
||||
JComboBox<Stage> relToCombo = new JComboBox<Stage>( 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<T>[] values) {
|
||||
ComboBoxModel<RocketComponent.Position> posRelModel = new EnumModel<RocketComponent.Position>(component, "RelativePositionMethod",
|
||||
ComboBoxModel<RocketComponent.Position> relativePositionMethodModel = new EnumModel<RocketComponent.Position>(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<RocketComponent.Position>( posRelModel );
|
||||
JComboBox<?> positionMethodCombo = new JComboBox<RocketComponent.Position>( 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<Stage> relativeStageModel = new StageSelectModel( stage );
|
||||
JComboBox<Stage> relToCombo = new JComboBox<Stage>( 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;
|
||||
}
|
||||
|
@ -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);
|
||||
|
@ -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<finCount; fin++) {
|
||||
RocketComponentShape[] finShape = new RocketComponentShape[ finCount];
|
||||
for (int finNum=0; finNum<finCount; finNum++) {
|
||||
Coordinate a;
|
||||
Path2D.Float p;
|
||||
|
||||
|
||||
// Make polygon
|
||||
p = new Path2D.Float();
|
||||
for (int i=0; i<finPoints.length; i++) {
|
||||
a = transformation.transform(finset.toAbsolute(finPoints[i])[0]);
|
||||
// previous version
|
||||
// a = transformation.transform(finset.toAbsolute(finPoints[i])[0]);
|
||||
a = transformation.transform(finSetFront.add(finPoints[i]));
|
||||
|
||||
if (i==0)
|
||||
p.moveTo(a.x*S, a.y*S);
|
||||
else
|
||||
@ -54,20 +58,20 @@ public class FinSetShapes extends RocketComponentShape {
|
||||
}
|
||||
|
||||
p.closePath();
|
||||
rcs[fin] = new RocketComponentShape( p, finset);
|
||||
finShape[finNum] = new RocketComponentShape( p, finset);
|
||||
|
||||
// Rotate fin coordinates
|
||||
for (int i=0; i<finPoints.length; i++)
|
||||
finPoints[i] = finRotation.transform(finPoints[i]);
|
||||
}
|
||||
|
||||
return rcs;
|
||||
return finShape;
|
||||
}
|
||||
|
||||
public static RocketComponentShape[] getShapesBack(
|
||||
net.sf.openrocket.rocketcomponent.RocketComponent component,
|
||||
Transformation transformation,
|
||||
Coordinate instanceOffset) {
|
||||
Coordinate componentAbsoluteLocation) {
|
||||
|
||||
net.sf.openrocket.rocketcomponent.FinSet finset = (net.sf.openrocket.rocketcomponent.FinSet)component;
|
||||
Shape[] toReturn;
|
||||
@ -90,7 +94,7 @@ public class FinSetShapes extends RocketComponentShape {
|
||||
double radius = finset.getBodyRadius();
|
||||
double thickness = finset.getThickness();
|
||||
double height = finset.getSpan();
|
||||
|
||||
Coordinate compCenter = finset.getAbsolutePositionVector();
|
||||
Transformation baseRotation = finset.getBaseRotationTransformation();
|
||||
Transformation finRotation = finset.getFinRotationTransformation();
|
||||
|
||||
@ -113,13 +117,13 @@ public class FinSetShapes extends RocketComponentShape {
|
||||
|
||||
// Make polygon
|
||||
p = new Path2D.Double();
|
||||
a = transformation.transform(finset.toAbsolute(c[0])[0]);
|
||||
a = transformation.transform(compCenter.add( c[0] ));
|
||||
p.moveTo(a.z*S, a.y*S);
|
||||
a = transformation.transform(finset.toAbsolute(c[1])[0]);
|
||||
a = transformation.transform(compCenter.add( c[1] ));
|
||||
p.lineTo(a.z*S, a.y*S);
|
||||
a = transformation.transform(finset.toAbsolute(c[2])[0]);
|
||||
a = transformation.transform(compCenter.add( c[2] ));
|
||||
p.lineTo(a.z*S, a.y*S);
|
||||
a = transformation.transform(finset.toAbsolute(c[3])[0]);
|
||||
a = transformation.transform(compCenter.add( c[3] ));
|
||||
p.lineTo(a.z*S, a.y*S);
|
||||
p.closePath();
|
||||
s[fin] = p;
|
||||
@ -222,10 +226,11 @@ public class FinSetShapes extends RocketComponentShape {
|
||||
Transformation t) {
|
||||
Path2D.Float p;
|
||||
|
||||
Coordinate compCenter = finset.getAbsolutePositionVector();
|
||||
// Make polygon
|
||||
p = new Path2D.Float();
|
||||
for (int i=0; i < array.length; i++) {
|
||||
Coordinate a = t.transform(finset.toAbsolute(array[i])[0]);
|
||||
Coordinate a = t.transform(compCenter.add( array[i]) );
|
||||
if (i==0)
|
||||
p.moveTo(a.z*S, a.y*S);
|
||||
else
|
||||
|
@ -14,7 +14,7 @@ public class RingComponentShapes extends RocketComponentShape {
|
||||
public static RocketComponentShape[] getShapesSide(
|
||||
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;
|
||||
@ -23,23 +23,23 @@ public class RingComponentShapes extends RocketComponentShape {
|
||||
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 ((or-ir >= 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);
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
|
@ -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<Coordinate> points = new ArrayList<Coordinate>();
|
||||
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;
|
||||
|
@ -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);
|
||||
|
@ -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<start.length; i++) {
|
||||
start[i] = baseRotation.transform(transformation.transform(start[i].add(0,bodyradius+outerradius,0)));
|
||||
start[i] = baseRotation.transform(transformation.transform(start[i].add(0,bodyRadius+outerRadius,0)));
|
||||
}
|
||||
|
||||
//start = baseRotation.transform(start);
|
||||
|
||||
Shape[] s = new Shape[fins];
|
||||
for (int i=0; i<fins; i++) {
|
||||
s[i] = new Rectangle2D.Double(start[0].x*S,(start[0].y-outerradius)*S,length*S,2*outerradius*S);
|
||||
s[i] = new Rectangle2D.Double(start[0].x*S,(start[0].y-outerRadius)*S,length*S,2*outerRadius*S);
|
||||
start = finRotation.transform(start);
|
||||
}
|
||||
return RocketComponentShape.toArray(s, component);
|
||||
@ -46,7 +47,7 @@ public class TubeFinSetShapes extends RocketComponentShape {
|
||||
public static RocketComponentShape[] getShapesBack(
|
||||
net.sf.openrocket.rocketcomponent.RocketComponent component,
|
||||
Transformation transformation,
|
||||
Coordinate instanceOffset) {
|
||||
Coordinate componentAbsoluteLocation) {
|
||||
|
||||
net.sf.openrocket.rocketcomponent.TubeFinSet finset = (net.sf.openrocket.rocketcomponent.TubeFinSet)component;
|
||||
|
||||
@ -54,7 +55,8 @@ public class TubeFinSetShapes extends RocketComponentShape {
|
||||
double outerradius = finset.getOuterRadius();
|
||||
double bodyradius = finset.getBodyRadius();
|
||||
|
||||
Coordinate[] start = finset.toAbsolute( instanceOffset);
|
||||
Coordinate[] start = new Coordinate[]{ transformation.transform( componentAbsoluteLocation.sub( 0, 0, 0) )};
|
||||
start = component.shiftCoordinates( start);
|
||||
|
||||
Transformation baseRotation = finset.getBaseRotationTransformation();
|
||||
Transformation finRotation = finset.getFinRotationTransformation();
|
||||
|
@ -24,10 +24,12 @@ import net.sf.openrocket.gui.util.ColorConversion;
|
||||
import net.sf.openrocket.gui.util.SwingPreferences;
|
||||
import net.sf.openrocket.motor.Motor;
|
||||
import net.sf.openrocket.rocketcomponent.Configuration;
|
||||
import net.sf.openrocket.rocketcomponent.FinSet;
|
||||
import net.sf.openrocket.rocketcomponent.MotorMount;
|
||||
import net.sf.openrocket.rocketcomponent.MultipleComponent;
|
||||
import net.sf.openrocket.rocketcomponent.Rocket;
|
||||
import net.sf.openrocket.rocketcomponent.RocketComponent;
|
||||
import net.sf.openrocket.rocketcomponent.Stage;
|
||||
import net.sf.openrocket.rocketcomponent.Transition;
|
||||
import net.sf.openrocket.gui.rocketfigure.RocketComponentShape;
|
||||
import net.sf.openrocket.gui.scalefigure.RocketPanel;
|
||||
import net.sf.openrocket.startup.Application;
|
||||
@ -186,9 +188,8 @@ public class RocketFigure extends AbstractScaleFigure {
|
||||
calculateSize();
|
||||
Rocket theRocket = configuration.getRocket();
|
||||
Coordinate zero = new Coordinate(0,0,0);
|
||||
getShapeTree( figureShapes, theRocket, zero);
|
||||
getShapeTree( figureShapes, theRocket, zero);
|
||||
|
||||
// System.err.println(" updating the RocketFigure.");
|
||||
repaint();
|
||||
fireChangeEvent();
|
||||
}
|
||||
@ -348,27 +349,32 @@ public class RocketFigure extends AbstractScaleFigure {
|
||||
while (iterator.hasNext()) {
|
||||
MotorMount mount = iterator.next();
|
||||
Motor motor = mount.getMotor(motorID);
|
||||
double length = motor.getLength();
|
||||
double radius = motor.getDiameter() / 2;
|
||||
double motorLength = motor.getLength();
|
||||
double motorRadius = motor.getDiameter() / 2;
|
||||
|
||||
Coordinate[] position = ((RocketComponent) mount).toAbsolute(
|
||||
new Coordinate(((RocketComponent) mount).getLength() +
|
||||
mount.getMotorOverhang() - length));
|
||||
RocketComponent mountComponent = ((RocketComponent) mount);
|
||||
Coordinate mountPosition = mountComponent.getAbsolutePositionVector();
|
||||
double mountLength = mountComponent.getLength();
|
||||
|
||||
Coordinate[] motorPositions;
|
||||
Coordinate[] clusterTop = new Coordinate[]{mountPosition.add( mountLength/2 - motorLength + mount.getMotorOverhang() , 0, 0)};
|
||||
|
||||
for (int i = 0; i < position.length; i++) {
|
||||
position[i] = transformation.transform(position[i]);
|
||||
motorPositions = mountComponent.shiftCoordinates(clusterTop);
|
||||
|
||||
for (int i = 0; i < motorPositions.length; i++) {
|
||||
motorPositions[i] = transformation.transform(motorPositions[i]);
|
||||
}
|
||||
|
||||
for (Coordinate coord : position) {
|
||||
for (Coordinate coord : motorPositions) {
|
||||
Shape s;
|
||||
if (currentViewType == RocketPanel.VIEW_TYPE.SideView) {
|
||||
s = new Rectangle2D.Double(EXTRA_SCALE * coord.x,
|
||||
EXTRA_SCALE * (coord.y - radius), EXTRA_SCALE * length,
|
||||
EXTRA_SCALE * 2 * radius);
|
||||
EXTRA_SCALE * (coord.y - motorRadius), EXTRA_SCALE * motorLength,
|
||||
EXTRA_SCALE * 2 * motorRadius);
|
||||
} else {
|
||||
s = new Ellipse2D.Double(EXTRA_SCALE * (coord.z - radius),
|
||||
EXTRA_SCALE * (coord.y - radius), EXTRA_SCALE * 2 * radius,
|
||||
EXTRA_SCALE * 2 * radius);
|
||||
s = new Ellipse2D.Double(EXTRA_SCALE * (coord.z - motorRadius),
|
||||
EXTRA_SCALE * (coord.y - motorRadius), EXTRA_SCALE * 2 * motorRadius,
|
||||
EXTRA_SCALE * 2 * motorRadius);
|
||||
}
|
||||
g2.setColor(fillColor);
|
||||
g2.fill(s);
|
||||
@ -433,53 +439,29 @@ public class RocketFigure extends AbstractScaleFigure {
|
||||
RocketPanel.VIEW_TYPE viewType = this.currentViewType;
|
||||
Transformation viewTransform = this.transformation;
|
||||
|
||||
Coordinate componentLocation = comp.getRelativePositionVector();
|
||||
// Coordinate componentRelativeLocation = comp.getRelativePositionVector();
|
||||
Coordinate componentAbsoluteLocation = parentOffset.add(comp.getRelativePositionVector());
|
||||
|
||||
if( comp instanceof MultipleComponent ){
|
||||
MultipleComponent multi = (MultipleComponent)comp;
|
||||
int instanceCount;
|
||||
instanceCount = multi.getInstanceCount();
|
||||
|
||||
// get the offsets for m instances
|
||||
Coordinate[] instanceOffsets = multi.getInstanceOffsets();
|
||||
|
||||
// replicate n children m times each
|
||||
int childCount = comp.getChildCount();
|
||||
ArrayList<RocketComponentShape> childrenToReplicate = new ArrayList<RocketComponentShape>();
|
||||
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;
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user