[fix][refactor] simplified rocketfigure drawing code
Fixes Issues: - https://github.com/openrocket/openrocket/issues/366 - https://github.com/openrocket/openrocket/issues/323 - RocketFigure no longer draws specific stages: Starts drawing rocket, and then propogates location, angle/transformation downwards - fixed active/inactive visibility toggling - Fixed Drowing Bounds for RocketFigure - Fix: FlightConfiguration#getBounds() - Fix: FinSet#getComponentBounds() - Fix: InnerTube#getInstanceCount() - Add: Coordinate#MIN, Coordinate#MAX - Add: net.sf.openrocket.util.BoundingBox - RocketComponent: - implement: #getInstanceLocations() // relative to parent component - implement #getInstanceAngles() - implement: #getComponentLocations() (Refactor/rename of #getLocations() ) - Implement <x>#getInstanceOffsets() // relative to component-reference-point - FinSet - PodSet - ParallelStage - RailButton - InnerTube: - fixed drawing shapes: - TubeShapes - BodyTube - Launch Lug - RingComponent (InnerTube, EngineBlock, Coupler) - Finset - Transition - Rail Button
This commit is contained in:
parent
c36ce2eae4
commit
eb72329c58
@ -1,6 +1,5 @@
|
||||
package net.sf.openrocket.rocketcomponent;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
|
||||
@ -12,6 +11,7 @@ import net.sf.openrocket.material.Material;
|
||||
import net.sf.openrocket.rocketcomponent.position.AxialPositionable;
|
||||
import net.sf.openrocket.startup.Application;
|
||||
import net.sf.openrocket.util.ArrayUtils;
|
||||
import net.sf.openrocket.util.BoundingBox;
|
||||
import net.sf.openrocket.util.Coordinate;
|
||||
import net.sf.openrocket.util.MathUtil;
|
||||
import net.sf.openrocket.util.Transformation;
|
||||
@ -168,7 +168,6 @@ public abstract class FinSet extends ExternalComponent implements RingInstanceab
|
||||
if (n > 8)
|
||||
n = 8;
|
||||
fins = n;
|
||||
finRotation = Transformation.rotate_x(2 * Math.PI / fins);
|
||||
fireComponentChangeEvent(ComponentChangeEvent.BOTH_CHANGE);
|
||||
}
|
||||
|
||||
@ -186,7 +185,7 @@ public abstract class FinSet extends ExternalComponent implements RingInstanceab
|
||||
|
||||
/**
|
||||
* Sets the base rotation amount of the first fin.
|
||||
* @param r The base rotation amount.
|
||||
* @param r The base rotation in radians
|
||||
*/
|
||||
public void setBaseRotation(double r) {
|
||||
setAngularOffset(r);
|
||||
@ -596,59 +595,18 @@ public abstract class FinSet extends ExternalComponent implements RingInstanceab
|
||||
*/
|
||||
@Override
|
||||
public Collection<Coordinate> getComponentBounds() {
|
||||
Collection<Coordinate> bounds = new ArrayList<Coordinate>(8);
|
||||
BoundingBox singleFinBounds= new BoundingBox( getFinPoints());
|
||||
final double finLength = singleFinBounds.max.x;
|
||||
final double finHeight = singleFinBounds.max.y;
|
||||
|
||||
// should simply return this component's bounds in this component's body frame.
|
||||
BoundingBox compBox = new BoundingBox( getComponentLocations() );
|
||||
|
||||
double x_min = Double.MAX_VALUE;
|
||||
double x_max = Double.MIN_VALUE;
|
||||
double r_max = 0.0;
|
||||
BoundingBox finSetBox = new BoundingBox( compBox.min.sub( 0, finHeight, finHeight ),
|
||||
compBox.max.add( finLength, finHeight, finHeight ));
|
||||
|
||||
for (Coordinate point : getFinPoints()) {
|
||||
double hypot = MathUtil.hypot(point.y, point.z);
|
||||
double x_cur = point.x;
|
||||
if (x_min > x_cur) {
|
||||
x_min = x_cur;
|
||||
}
|
||||
if (x_max < x_cur) {
|
||||
x_max = x_cur;
|
||||
}
|
||||
if (r_max < hypot) {
|
||||
r_max = hypot;
|
||||
}
|
||||
}
|
||||
|
||||
addBoundingBox(bounds, x_min, x_max, r_max);
|
||||
return bounds;
|
||||
return finSetBox.toCollection();
|
||||
}
|
||||
|
||||
// /**
|
||||
// * Adds the 2d-coordinate bound (x,y) to the collection for both z-components and for
|
||||
// * all fin rotations.
|
||||
// */
|
||||
// private void addFinBound(Collection<Coordinate> set, double x, double y) {
|
||||
// Coordinate c;
|
||||
// int i;
|
||||
//
|
||||
// c = new Coordinate(x, y, thickness / 2);
|
||||
// c = baseRotation.transform(c);
|
||||
// set.add(c);
|
||||
// for (i = 1; i < fins; i++) {
|
||||
// c = finRotation.transform(c);
|
||||
// set.add(c);
|
||||
// }
|
||||
//
|
||||
// c = new Coordinate(x, y, -thickness / 2);
|
||||
// c = baseRotation.transform(c);
|
||||
// set.add(c);
|
||||
// for (i = 1; i < fins; i++) {
|
||||
// c = finRotation.transform(c);
|
||||
// set.add(c);
|
||||
// }
|
||||
// }
|
||||
//
|
||||
//
|
||||
|
||||
@Override
|
||||
public void componentChanged(ComponentChangeEvent e) {
|
||||
if (e.isAerodynamicChange()) {
|
||||
@ -672,8 +630,7 @@ public abstract class FinSet extends ExternalComponent implements RingInstanceab
|
||||
s = this.getParent();
|
||||
while (s != null) {
|
||||
if (s instanceof SymmetricComponent) {
|
||||
double x = this.toRelative(new Coordinate(0, 0, 0), s)[0].x;
|
||||
return ((SymmetricComponent) s).getRadius(x);
|
||||
return ((SymmetricComponent) s).getRadius( this.position.x);
|
||||
}
|
||||
s = s.getParent();
|
||||
}
|
||||
@ -747,16 +704,6 @@ public abstract class FinSet extends ExternalComponent implements RingInstanceab
|
||||
|
||||
@Override
|
||||
public double getAngularOffset() {
|
||||
ComponentAssembly stage = this.getAssembly();
|
||||
if( PodSet.class.isAssignableFrom( stage.getClass() )){
|
||||
PodSet assembly= (PodSet)stage;
|
||||
return assembly.getAngularOffset() + baseRotationValue;
|
||||
}else if( ParallelStage.class.isAssignableFrom( stage.getClass())){
|
||||
ParallelStage assembly = (ParallelStage)stage;
|
||||
log.debug("detected p-stage with position: "+assembly.getAngularOffset());
|
||||
return assembly.getAngularOffset() + baseRotationValue;
|
||||
}
|
||||
|
||||
return baseRotationValue;
|
||||
}
|
||||
|
||||
@ -782,12 +729,32 @@ public abstract class FinSet extends ExternalComponent implements RingInstanceab
|
||||
|
||||
double[] result = new double[ getFinCount()];
|
||||
for( int i=0; i<getFinCount(); ++i){
|
||||
result[i] = baseAngle + incrAngle*i;
|
||||
double currentAngle = baseAngle + incrAngle*i;
|
||||
if( Math.PI*2 <= currentAngle)
|
||||
currentAngle -= Math.PI*2;
|
||||
result[i] = currentAngle;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Coordinate[] getInstanceOffsets(){
|
||||
checkState();
|
||||
|
||||
final int finCount = getFinCount();
|
||||
double radius = this.getBodyRadius();
|
||||
Coordinate[] toReturn = new Coordinate[finCount];
|
||||
final double[] angles = getInstanceAngles();
|
||||
for (int instanceNumber = 0; instanceNumber < finCount; instanceNumber++) {
|
||||
final double curY = radius * Math.cos(angles[instanceNumber]);
|
||||
final double curZ = radius * Math.sin(angles[instanceNumber]);
|
||||
toReturn[instanceNumber] = new Coordinate(0, curY, curZ );
|
||||
}
|
||||
|
||||
return toReturn;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Position getAxialPositionMethod( ){
|
||||
return getRelativePositionMethod();
|
||||
|
||||
@ -14,6 +14,7 @@ import net.sf.openrocket.motor.MotorConfiguration;
|
||||
import net.sf.openrocket.motor.MotorConfigurationId;
|
||||
import net.sf.openrocket.startup.Application;
|
||||
import net.sf.openrocket.util.ArrayList;
|
||||
import net.sf.openrocket.util.BoundingBox;
|
||||
import net.sf.openrocket.util.Coordinate;
|
||||
import net.sf.openrocket.util.MathUtil;
|
||||
import net.sf.openrocket.util.Monitorable;
|
||||
@ -60,7 +61,7 @@ public class FlightConfiguration implements FlightConfigurableParameter<FlightCo
|
||||
final protected HashMap<MotorConfigurationId, MotorConfiguration> motors = new HashMap<MotorConfigurationId, MotorConfiguration>();
|
||||
|
||||
private int boundsModID = -1;
|
||||
private ArrayList<Coordinate> cachedBounds = new ArrayList<Coordinate>();
|
||||
private BoundingBox cachedBounds = new BoundingBox();
|
||||
private double cachedLength = -1;
|
||||
|
||||
private int refLengthModID = -1;
|
||||
@ -159,8 +160,8 @@ public class FlightConfiguration implements FlightConfigurableParameter<FlightCo
|
||||
* Check whether the stage specified by the index is active.
|
||||
*/
|
||||
public boolean isStageActive(int stageNumber) {
|
||||
if( ! stages.containsKey(stageNumber)){
|
||||
throw new IllegalArgumentException(" Configuration does not contain stage number: "+stageNumber);
|
||||
if( -1 == stageNumber ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return stages.get(stageNumber).active;
|
||||
@ -397,30 +398,27 @@ public class FlightConfiguration implements FlightConfigurableParameter<FlightCo
|
||||
public Collection<Coordinate> getBounds() {
|
||||
if (rocket.getModID() != boundsModID) {
|
||||
boundsModID = rocket.getModID();
|
||||
cachedBounds.clear();
|
||||
|
||||
double minX = Double.POSITIVE_INFINITY, maxX = Double.NEGATIVE_INFINITY;
|
||||
// System.err.println(String.format(">> generating bounds for configuration: %s (%d)(%s)", getName(), this.instanceNumber, getId() ));
|
||||
|
||||
BoundingBox bounds = new BoundingBox();
|
||||
|
||||
for (RocketComponent component : this.getActiveComponents()) {
|
||||
for (Coordinate coord : component.getComponentBounds()) {
|
||||
cachedBounds.add(coord);
|
||||
if (coord.x < minX){
|
||||
minX = coord.x;
|
||||
}else if (coord.x > maxX){
|
||||
maxX = coord.x;
|
||||
}
|
||||
}
|
||||
BoundingBox componentBounds = new BoundingBox( component.getComponentBounds() );
|
||||
|
||||
bounds.compare( componentBounds );
|
||||
|
||||
// System.err.println(String.format(" [%s] %s >> %s", component.getName(), componentBounds.toString(), bounds.toString() ));
|
||||
}
|
||||
|
||||
if (Double.isInfinite(minX) || Double.isInfinite(maxX)) {
|
||||
cachedLength = 0;
|
||||
} else {
|
||||
cachedLength = maxX - minX;
|
||||
}
|
||||
cachedLength = bounds.span().x;
|
||||
|
||||
cachedBounds.compare( bounds );
|
||||
}
|
||||
return cachedBounds.clone();
|
||||
|
||||
return cachedBounds.toCollection();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Returns the length of the rocket configuration, from the foremost bound X-coordinate
|
||||
* to the aft-most X-coordinate. The value is cached.
|
||||
|
||||
@ -145,7 +145,7 @@ public class InnerTube extends ThicknessRingComponent implements Clusterable, Ra
|
||||
|
||||
@Override
|
||||
public int getInstanceCount() {
|
||||
return this.getLocations().length;
|
||||
return cluster.getClusterCount();
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -226,23 +226,12 @@ public class InnerTube extends ThicknessRingComponent implements Clusterable, Ra
|
||||
@Override
|
||||
public Coordinate[] getInstanceOffsets(){
|
||||
|
||||
int instanceCount = getClusterCount();
|
||||
if (instanceCount == 1)
|
||||
return super.getInstanceOffsets();
|
||||
if ( 1 == getClusterCount())
|
||||
return new Coordinate[] { Coordinate.ZERO };
|
||||
|
||||
List<Coordinate> points = getClusterPoints();
|
||||
if (points.size() != instanceCount) {
|
||||
throw new BugException("Inconsistent cluster configuration, cluster count(" + instanceCount +
|
||||
") != point count(" + points.size()+")");
|
||||
}
|
||||
|
||||
|
||||
Coordinate[] newArray = new Coordinate[ instanceCount];
|
||||
for (int instanceNumber = 0; instanceNumber < instanceCount; instanceNumber++) {
|
||||
newArray[ instanceNumber] = this.position.add( points.get(instanceNumber));
|
||||
}
|
||||
|
||||
return newArray;
|
||||
return points.toArray( new Coordinate[ points.size()]);
|
||||
}
|
||||
|
||||
// @Override
|
||||
|
||||
@ -3,17 +3,21 @@ package net.sf.openrocket.rocketcomponent;
|
||||
import net.sf.openrocket.util.Coordinate;
|
||||
|
||||
public interface Instanceable {
|
||||
|
||||
/**
|
||||
* Note: <code> this.getLocation().length == this.getInstanceCount() </code> should ALWAYS be true. If getInstanceCount() returns anything besides 1,
|
||||
* this function should be override as well.
|
||||
*
|
||||
* Note: This is function has a concrete implementation in RocketComponent.java ... it is included here only as a reminder.
|
||||
*
|
||||
* @return coordinates of each instance of this component -- specifically the front center of each instance in global coordinates
|
||||
*/
|
||||
|
||||
@Deprecated
|
||||
public Coordinate[] getLocations();
|
||||
|
||||
/**
|
||||
* Returns vector coordinates of each instance of this component relative to this component's parent
|
||||
*
|
||||
* Note: <code> this.getOffsets().length == this.getInstanceCount() </code> should ALWAYS be true.
|
||||
* If getInstanceCount() returns anything besides 1 this function should be overridden as well.
|
||||
*
|
||||
*
|
||||
* @return coordinates location of each instance relative to component's parent
|
||||
*/
|
||||
public Coordinate[] getInstanceLocations();
|
||||
|
||||
/**
|
||||
* Returns vector coordinates of each instance of this component relative to this component's reference point (typically front center)
|
||||
*
|
||||
|
||||
@ -127,17 +127,15 @@ public class LaunchLug extends ExternalComponent implements Coaxial, LineInstanc
|
||||
return ComponentPreset.Type.LAUNCH_LUG;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public Coordinate[] getInstanceOffsets(){
|
||||
Coordinate[] toReturn = new Coordinate[this.getInstanceCount()];
|
||||
|
||||
final double xOffset = this.position.x;
|
||||
final double yOffset = Math.cos(radialDirection) * (radialDistance);
|
||||
final double zOffset = Math.sin(radialDirection) * (radialDistance);
|
||||
|
||||
for ( int index=0; index < this.getInstanceCount(); index++){
|
||||
toReturn[index] = new Coordinate(xOffset + index*this.instanceSeparation, yOffset, zOffset);
|
||||
toReturn[index] = new Coordinate(index*this.instanceSeparation, yOffset, zOffset);
|
||||
}
|
||||
|
||||
return toReturn;
|
||||
|
||||
@ -128,28 +128,7 @@ public class ParallelStage extends AxialStage implements FlightConfigurableCompo
|
||||
public double getRadialOffset() {
|
||||
return this.radialPosition_m;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Coordinate[] getInstanceOffsets(){
|
||||
checkState();
|
||||
|
||||
Coordinate center = Coordinate.ZERO;
|
||||
Coordinate[] toReturn = new Coordinate[this.instanceCount];
|
||||
final double[] angles = getInstanceAngles();
|
||||
for (int instanceNumber = 0; instanceNumber < this.instanceCount; instanceNumber++) {
|
||||
final double curY = this.radialPosition_m * Math.cos(angles[instanceNumber]);
|
||||
final double curZ = this.radialPosition_m * Math.sin(angles[instanceNumber]);
|
||||
toReturn[instanceNumber] = center.add(0, curY, curZ );
|
||||
}
|
||||
|
||||
return toReturn;
|
||||
}
|
||||
|
||||
@Override
|
||||
public double getInstanceAngleIncrement(){
|
||||
return this.angularSeparation;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public double[] getInstanceAngles(){
|
||||
final double baseAngle = getAngularOffset();
|
||||
@ -163,23 +142,21 @@ public class ParallelStage extends AxialStage implements FlightConfigurableCompo
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public double getInstanceAngleIncrement(){
|
||||
return this.angularSeparation;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Coordinate[] getLocations() {
|
||||
if (null == this.parent) {
|
||||
throw new BugException(" Attempted to get absolute position Vector of a Stage without a parent. ");
|
||||
}
|
||||
public Coordinate[] getInstanceOffsets(){
|
||||
checkState();
|
||||
|
||||
Coordinate[] parentInstances = this.parent.getLocations();
|
||||
if (1 != parentInstances.length) {
|
||||
throw new BugException(" OpenRocket does not (yet) support external stages attached to external stages. " +
|
||||
"(assumed reason for getting multiple parent locations into an external stage.)");
|
||||
}
|
||||
|
||||
final Coordinate center = parentInstances[0].add( this.position);
|
||||
Coordinate[] instanceLocations = this.getInstanceOffsets();
|
||||
Coordinate[] toReturn = new Coordinate[ instanceLocations.length];
|
||||
for( int i = 0; i < toReturn.length; i++){
|
||||
toReturn[i] = center.add( instanceLocations[i]);
|
||||
Coordinate[] toReturn = new Coordinate[this.instanceCount];
|
||||
final double[] angles = getInstanceAngles();
|
||||
for (int instanceNumber = 0; instanceNumber < this.instanceCount; instanceNumber++) {
|
||||
final double curY = this.radialPosition_m * Math.cos(angles[instanceNumber]);
|
||||
final double curZ = this.radialPosition_m * Math.sin(angles[instanceNumber]);
|
||||
toReturn[instanceNumber] = new Coordinate(0, curY, curZ );
|
||||
}
|
||||
|
||||
return toReturn;
|
||||
|
||||
@ -76,22 +76,7 @@ public class PodSet extends ComponentAssembly implements RingInstanceable {
|
||||
public boolean isCompatible(Class<? extends RocketComponent> type) {
|
||||
return BodyComponent.class.isAssignableFrom(type);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Coordinate[] getInstanceOffsets(){
|
||||
checkState();
|
||||
|
||||
Coordinate center = Coordinate.ZERO;
|
||||
Coordinate[] toReturn = new Coordinate[this.instanceCount];
|
||||
final double[] angles = getInstanceAngles();
|
||||
for (int instanceNumber = 0; instanceNumber < this.instanceCount; instanceNumber++) {
|
||||
final double curY = this.radialPosition_m * Math.cos(angles[instanceNumber]);
|
||||
final double curZ = this.radialPosition_m * Math.sin(angles[instanceNumber]);
|
||||
toReturn[instanceNumber] = center.add(0, curY, curZ );
|
||||
}
|
||||
|
||||
return toReturn;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public double getInstanceAngleIncrement(){
|
||||
@ -112,30 +97,18 @@ public class PodSet extends ComponentAssembly implements RingInstanceable {
|
||||
}
|
||||
|
||||
@Override
|
||||
public Coordinate[] getLocations() {
|
||||
if (null == this.parent) {
|
||||
throw new BugException(" Attempted to get absolute position Vector of a Stage without a parent. ");
|
||||
}
|
||||
|
||||
if (this.isAfter()) {
|
||||
return super.getLocations();
|
||||
} else {
|
||||
Coordinate[] parentInstances = this.parent.getLocations();
|
||||
if (1 != parentInstances.length) {
|
||||
throw new BugException(" OpenRocket does not (yet) support external stages attached to external stages. " +
|
||||
"(assumed reason for getting multiple parent locations into an external stage.)");
|
||||
}
|
||||
|
||||
final Coordinate center = parentInstances[0].add( this.position);
|
||||
Coordinate[] instanceLocations = this.getInstanceOffsets();
|
||||
Coordinate[] toReturn = new Coordinate[ instanceLocations.length];
|
||||
for( int i = 0; i < toReturn.length; i++){
|
||||
toReturn[i] = center.add( instanceLocations[i]);
|
||||
}
|
||||
|
||||
return toReturn;
|
||||
public Coordinate[] getInstanceOffsets(){
|
||||
checkState();
|
||||
|
||||
Coordinate[] toReturn = new Coordinate[this.instanceCount];
|
||||
final double[] angles = getInstanceAngles();
|
||||
for (int instanceNumber = 0; instanceNumber < this.instanceCount; instanceNumber++) {
|
||||
final double curY = this.radialPosition_m * Math.cos(angles[instanceNumber]);
|
||||
final double curZ = this.radialPosition_m * Math.sin(angles[instanceNumber]);
|
||||
toReturn[instanceNumber] = new Coordinate(0, curY, curZ );
|
||||
}
|
||||
|
||||
return toReturn;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@ -196,24 +196,15 @@ public class RailButton extends ExternalComponent implements LineInstanceable {
|
||||
fireComponentChangeEvent(ComponentChangeEvent.AERODYNAMIC_CHANGE);
|
||||
}
|
||||
|
||||
|
||||
// @Override
|
||||
// public void setPositionValue(double value) {
|
||||
// super.setPositionValue(value);
|
||||
// fireComponentChangeEvent(ComponentChangeEvent.BOTH_CHANGE);
|
||||
// }
|
||||
|
||||
|
||||
@Override
|
||||
public Coordinate[] getInstanceOffsets(){
|
||||
Coordinate[] toReturn = new Coordinate[this.getInstanceCount()];
|
||||
|
||||
final double xOffset = this.position.x;
|
||||
final double yOffset = Math.cos(this.angle_rad) * ( this.radialDistance_m );
|
||||
final double zOffset = Math.sin(this.angle_rad) * ( this.radialDistance_m );
|
||||
|
||||
for ( int index=0; index < this.getInstanceCount(); index++){
|
||||
toReturn[index] = new Coordinate(xOffset + index*this.instanceSeparation, yOffset, zOffset);
|
||||
toReturn[index] = new Coordinate(index*this.instanceSeparation, yOffset, zOffset);
|
||||
}
|
||||
|
||||
return toReturn;
|
||||
|
||||
@ -210,6 +210,11 @@ public class Rocket extends ComponentAssembly {
|
||||
return (AxialStage) children.get( children.size()-1 );
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getStageNumber() {
|
||||
// invalid, error value
|
||||
return -1;
|
||||
}
|
||||
private int getNewStageNumber() {
|
||||
int guess = 0;
|
||||
while (stageMap.containsKey(guess)) {
|
||||
|
||||
@ -1174,20 +1174,47 @@ public abstract class RocketComponent implements ChangeSource, Cloneable, Iterab
|
||||
* of the passed array and return the array itself.
|
||||
*/
|
||||
// @Override Me !
|
||||
public Coordinate[] getInstanceLocations(){
|
||||
int instanceCount = getInstanceCount();
|
||||
if( 0 == instanceCount ){
|
||||
return new Coordinate[]{this.position};
|
||||
}
|
||||
|
||||
checkState();
|
||||
|
||||
Coordinate center = this.position;
|
||||
Coordinate[] offsets = getInstanceOffsets();
|
||||
|
||||
Coordinate[] locations= new Coordinate[offsets.length];
|
||||
for (int instanceNumber = 0; instanceNumber < locations.length; instanceNumber++) {
|
||||
locations[instanceNumber] = center.add( offsets[instanceNumber] );
|
||||
}
|
||||
|
||||
return locations;
|
||||
}
|
||||
|
||||
public Coordinate[] getInstanceOffsets(){
|
||||
return new Coordinate[]{this.position};
|
||||
// According to the language specification, Java will initialized double values to 0.0
|
||||
return new Coordinate[]{Coordinate.ZERO};
|
||||
}
|
||||
|
||||
// this is an inefficient way to calculate all of the locations;
|
||||
// it also breaks locality, (i.e. is a rocket-wide calculation )
|
||||
@Deprecated
|
||||
public Coordinate[] getLocations() {
|
||||
return getComponentLocations();
|
||||
}
|
||||
|
||||
public Coordinate[] getLocations() {
|
||||
public Coordinate[] getComponentLocations() {
|
||||
if (null == this.parent) {
|
||||
// == improperly initialized components OR the root Rocket instance
|
||||
return new Coordinate[] { Coordinate.ZERO };
|
||||
return getInstanceOffsets();
|
||||
} else {
|
||||
Coordinate[] parentPositions = this.parent.getLocations();
|
||||
int parentCount = parentPositions.length;
|
||||
|
||||
// override <instance>.getInstanceOffsets() in the subclass you want to fix.
|
||||
Coordinate[] instanceOffsets = this.getInstanceOffsets();
|
||||
Coordinate[] instanceOffsets = this.getInstanceLocations();
|
||||
int instanceCount = instanceOffsets.length;
|
||||
|
||||
// usual case optimization
|
||||
@ -1209,6 +1236,10 @@ public abstract class RocketComponent implements ChangeSource, Cloneable, Iterab
|
||||
}
|
||||
}
|
||||
|
||||
public double[] getInstanceAngles(){
|
||||
return new double[getInstanceCount()];
|
||||
}
|
||||
|
||||
/////////// Coordinate changes ///////////
|
||||
|
||||
/**
|
||||
@ -1954,11 +1985,11 @@ public abstract class RocketComponent implements ChangeSource, Cloneable, Iterab
|
||||
|
||||
|
||||
/**
|
||||
* Helper method to add eight bounds in a box around the rocket centerline. This box will be (x_max - x_min) long, and 2*r wide/high.
|
||||
* Helper method to add two points on opposite corners of a box around the rocket centerline. This box will be (x_max - x_min) long, and 2*r wide/high.
|
||||
*/
|
||||
protected static final void addBoundingBox(Collection<Coordinate> bounds, double x_min, double x_max, double r) {
|
||||
addBound(bounds, x_min, r);
|
||||
addBound(bounds, x_max, r);
|
||||
bounds.add(new Coordinate(x_min, -r, -r));
|
||||
bounds.add(new Coordinate(x_max, r, r));
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
91
core/src/net/sf/openrocket/util/BoundingBox.java
Normal file
91
core/src/net/sf/openrocket/util/BoundingBox.java
Normal file
@ -0,0 +1,91 @@
|
||||
package net.sf.openrocket.util;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
|
||||
public class BoundingBox {
|
||||
public Coordinate min;
|
||||
public Coordinate max;
|
||||
|
||||
public BoundingBox() {
|
||||
min = Coordinate.MAX.setWeight( 0.0);
|
||||
max = Coordinate.MIN.setWeight( 0.0);
|
||||
}
|
||||
|
||||
public BoundingBox( Coordinate _min, Coordinate _max) {
|
||||
this();
|
||||
this.min = _min.clone();
|
||||
this.max = _max.clone();
|
||||
}
|
||||
|
||||
public BoundingBox( Coordinate[] list ) {
|
||||
this();
|
||||
this.compare( list);
|
||||
}
|
||||
|
||||
public BoundingBox( Collection<Coordinate> list ) {
|
||||
this();
|
||||
this.compare( list.toArray( new Coordinate[0] ));
|
||||
}
|
||||
|
||||
@Override
|
||||
public BoundingBox clone() {
|
||||
return new BoundingBox( this.min, this.max );
|
||||
}
|
||||
|
||||
public void compare( Coordinate c ) {
|
||||
compare_against_min(c);
|
||||
compare_against_max(c);
|
||||
}
|
||||
|
||||
protected void compare_against_min( Coordinate c ) {
|
||||
if( min.x > c.x )
|
||||
min = min.setX( c.x );
|
||||
if( min.y > c.y )
|
||||
min = min.setY( c.y );
|
||||
if( min.z > c.z )
|
||||
min = min.setZ( c.z );
|
||||
}
|
||||
|
||||
protected void compare_against_max( Coordinate c) {
|
||||
if( max.x < c.x )
|
||||
max = max.setX( c.x );
|
||||
if( max.y < c.y )
|
||||
max = max.setY( c.y );
|
||||
if( max.z < c.z )
|
||||
max = max.setZ( c.z );
|
||||
}
|
||||
|
||||
public BoundingBox compare( Coordinate[] list ) {
|
||||
for( Coordinate c: list ) {
|
||||
compare( c );
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
public void compare( BoundingBox other ) {
|
||||
compare_against_min( other.min);
|
||||
compare_against_max( other.max);
|
||||
}
|
||||
|
||||
public Coordinate span() { return max.sub( min ); }
|
||||
|
||||
public Coordinate[] toArray() {
|
||||
return new Coordinate[] { this.min, this.max };
|
||||
}
|
||||
|
||||
public Collection<Coordinate> toCollection(){
|
||||
Collection<Coordinate> toReturn = new ArrayList<Coordinate>();
|
||||
toReturn.add( this.max);
|
||||
toReturn.add( this.min);
|
||||
return toReturn;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
// return String.format("[( %6.4f, %6.4f, %6.4f) < ( %6.4f, %6.4f, %6.4f)]",
|
||||
return String.format("[( %g, %g, %g) < ( %g, %g, %g)]",
|
||||
min.x, min.y, min.z,
|
||||
max.x, max.y, max.z );
|
||||
}
|
||||
}
|
||||
@ -63,6 +63,8 @@ public final class Coordinate implements Cloneable, Serializable {
|
||||
public static final Coordinate NUL = new Coordinate(0, 0, 0, 0);
|
||||
public static final Coordinate NaN = new Coordinate(Double.NaN, Double.NaN,
|
||||
Double.NaN, Double.NaN);
|
||||
public static final Coordinate MAX = new Coordinate(Double.MAX_VALUE,Double.MAX_VALUE,Double.MAX_VALUE,Double.MAX_VALUE);
|
||||
public static final Coordinate MIN = new Coordinate(Double.MIN_VALUE,Double.MIN_VALUE,Double.MIN_VALUE,Double.MIN_VALUE);
|
||||
|
||||
public final double x, y, z;
|
||||
public final double weight;
|
||||
|
||||
@ -242,6 +242,19 @@ public class Transformation implements java.io.Serializable {
|
||||
System.out.println();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
StringBuffer sb = new StringBuffer();
|
||||
|
||||
sb.append(String.format("[%3.2f %3.2f %3.2f] [%3.2f]\n",
|
||||
rotation[X][X],rotation[X][Y],rotation[X][Z],translate.x));
|
||||
sb.append(String.format("[%3.2f %3.2f %3.2f] + [%3.2f]\n",
|
||||
rotation[Y][X],rotation[Y][Y],rotation[Y][Z],translate.y));
|
||||
sb.append(String.format("[%3.2f %3.2f %3.2f] [%3.2f]\n",
|
||||
rotation[Z][X],rotation[Z][Y],rotation[Z][Z],translate.z));
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public boolean equals(Object other) {
|
||||
|
||||
@ -57,6 +57,83 @@ public class FinSetTest extends BaseTestCase {
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testInstancePoints_PI_2_BaseRotation() {
|
||||
// This is a simple square fin with sides of 1.0.
|
||||
TrapezoidFinSet fins = new TrapezoidFinSet();
|
||||
fins.setFinCount(4);
|
||||
fins.setFinShape(1.0, 1.0, 0.0, 1.0, .005);
|
||||
fins.setBaseRotation( Math.PI/2 );
|
||||
|
||||
BodyTube body = new BodyTube(1.0, 0.05 );
|
||||
body.addChild( fins );
|
||||
|
||||
Coordinate[] points = fins.getInstanceOffsets();
|
||||
|
||||
assertEquals( 0, points[0].x, 0.00001);
|
||||
assertEquals( 0, points[0].y, 0.00001);
|
||||
assertEquals( 0.05, points[0].z, 0.00001);
|
||||
|
||||
assertEquals( 0, points[1].x, 0.00001);
|
||||
assertEquals( -0.05, points[1].y, 0.00001);
|
||||
assertEquals( 0, points[1].z, 0.00001);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testInstancePoints_PI_4_BaseRotation() {
|
||||
// This is a simple square fin with sides of 1.0.
|
||||
TrapezoidFinSet fins = new TrapezoidFinSet();
|
||||
fins.setFinCount(4);
|
||||
fins.setFinShape(1.0, 1.0, 0.0, 1.0, .005);
|
||||
fins.setBaseRotation( Math.PI/4 );
|
||||
|
||||
BodyTube body = new BodyTube(1.0, 0.05 );
|
||||
body.addChild( fins );
|
||||
|
||||
Coordinate[] points = fins.getInstanceOffsets();
|
||||
|
||||
assertEquals( 0, points[0].x, 0.0001);
|
||||
assertEquals( 0.03535, points[0].y, 0.0001);
|
||||
assertEquals( 0.03535, points[0].z, 0.0001);
|
||||
|
||||
assertEquals( 0, points[1].x, 0.0001);
|
||||
assertEquals( -0.03535, points[1].y, 0.0001);
|
||||
assertEquals( 0.03535, points[1].z, 0.0001);
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void testInstanceAngles_zeroBaseRotation() {
|
||||
// This is a simple square fin with sides of 1.0.
|
||||
TrapezoidFinSet fins = new TrapezoidFinSet();
|
||||
fins.setFinCount(4);
|
||||
fins.setFinShape(1.0, 1.0, 0.0, 1.0, .005);
|
||||
fins.setBaseRotation( 0.0 );
|
||||
|
||||
double[] angles = fins.getInstanceAngles();
|
||||
|
||||
assertEquals( angles[0], 0, 0.000001 );
|
||||
assertEquals( angles[1], Math.PI/2, 0.000001 );
|
||||
assertEquals( angles[2], Math.PI, 0.000001 );
|
||||
assertEquals( angles[3], 1.5*Math.PI, 0.000001 );
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testInstanceAngles_90_BaseRotation() {
|
||||
// This is a simple square fin with sides of 1.0.
|
||||
TrapezoidFinSet fins = new TrapezoidFinSet();
|
||||
fins.setFinCount(4);
|
||||
fins.setFinShape(1.0, 1.0, 0.0, 1.0, .005);
|
||||
fins.setBaseRotation( Math.PI/2 );
|
||||
|
||||
double[] angles = fins.getInstanceAngles();
|
||||
|
||||
assertEquals( angles[0], Math.PI/2, 0.000001 );
|
||||
assertEquals( angles[1], Math.PI, 0.000001 );
|
||||
assertEquals( angles[2], 1.5*Math.PI, 0.000001 );
|
||||
assertEquals( angles[3], 0, 0.000001 );
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testFreeformCGComputation() throws Exception {
|
||||
|
||||
|
||||
@ -1,60 +1,41 @@
|
||||
package net.sf.openrocket.gui.rocketfigure;
|
||||
|
||||
import java.awt.Shape;
|
||||
import java.awt.geom.Ellipse2D;
|
||||
import java.awt.geom.Rectangle2D;
|
||||
|
||||
import net.sf.openrocket.rocketcomponent.BodyTube;
|
||||
import net.sf.openrocket.rocketcomponent.RocketComponent;
|
||||
import net.sf.openrocket.util.Coordinate;
|
||||
import net.sf.openrocket.util.Transformation;
|
||||
|
||||
|
||||
public class BodyTubeShapes extends RocketComponentShape {
|
||||
|
||||
public static RocketComponentShape[] getShapesSide(
|
||||
net.sf.openrocket.rocketcomponent.RocketComponent component,
|
||||
RocketComponent component,
|
||||
Transformation transformation,
|
||||
Coordinate componentAbsoluteLocation) {
|
||||
net.sf.openrocket.rocketcomponent.BodyTube tube = (net.sf.openrocket.rocketcomponent.BodyTube)component;
|
||||
|
||||
Coordinate componentAbsoluteLocation){
|
||||
|
||||
BodyTube tube = (BodyTube)component;
|
||||
|
||||
double length = tube.getLength();
|
||||
double radius = tube.getOuterRadius();
|
||||
|
||||
// old version
|
||||
//Coordinate[] instanceOffsets = new Coordinate[]{ transformation.transform( componentAbsoluteLocation )};
|
||||
//instanceOffsets = component.shiftCoordinates(instanceOffsets);
|
||||
|
||||
// new version
|
||||
Coordinate[] instanceOffsets = transformation.transform( component.getLocations());
|
||||
Shape[] s = new Shape[1];
|
||||
s[0] = TubeShapes.getShapesSide( transformation, componentAbsoluteLocation, length, radius );
|
||||
|
||||
Shape[] s = new Shape[instanceOffsets.length];
|
||||
for (int i=0; i < instanceOffsets.length; i++) {
|
||||
s[i] = new Rectangle2D.Double((instanceOffsets[i].x)*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);
|
||||
return RocketComponentShape.toArray(s, component);
|
||||
}
|
||||
|
||||
public static RocketComponentShape[] getShapesBack(
|
||||
net.sf.openrocket.rocketcomponent.RocketComponent component,
|
||||
RocketComponent component,
|
||||
Transformation transformation,
|
||||
Coordinate componentAbsoluteLocation) {
|
||||
net.sf.openrocket.rocketcomponent.BodyTube tube = (net.sf.openrocket.rocketcomponent.BodyTube)component;
|
||||
|
||||
double or = tube.getOuterRadius();
|
||||
|
||||
Coordinate[] instanceOffsets = new Coordinate[]{ transformation.transform( componentAbsoluteLocation )};
|
||||
//instanceOffsets = component.shiftCoordinates(instanceOffsets);
|
||||
|
||||
instanceOffsets = component.getLocations();
|
||||
BodyTube tube = (BodyTube)component;
|
||||
|
||||
double radius = tube.getOuterRadius();
|
||||
|
||||
|
||||
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);
|
||||
}
|
||||
Shape[] s = new Shape[1];
|
||||
s[0] = TubeShapes.getShapesBack( transformation, componentAbsoluteLocation, radius);
|
||||
|
||||
return RocketComponentShape.toArray(s, component);
|
||||
}
|
||||
|
||||
@ -15,56 +15,34 @@ public class FinSetShapes extends RocketComponentShape {
|
||||
public static RocketComponentShape[] getShapesSide(
|
||||
net.sf.openrocket.rocketcomponent.RocketComponent component,
|
||||
Transformation transformation,
|
||||
Coordinate componentAbsoluteLocation) {
|
||||
Coordinate instanceAbsoluteLocation) {
|
||||
net.sf.openrocket.rocketcomponent.FinSet finset = (net.sf.openrocket.rocketcomponent.FinSet)component;
|
||||
|
||||
|
||||
int finCount = finset.getFinCount();
|
||||
Transformation cantRotation = finset.getCantRotation();
|
||||
Transformation baseRotation = Transformation.rotate_x(finset.getAngularOffset()); // rotation about x-axis
|
||||
Transformation finRotation = finset.getFinRotationTransformation();
|
||||
|
||||
Coordinate finSetFront = componentAbsoluteLocation;
|
||||
Coordinate finSetFront = instanceAbsoluteLocation;
|
||||
Coordinate finPoints[] = finset.getFinPointsWithTab();
|
||||
|
||||
// TODO: MEDIUM: sloping radius
|
||||
double radius = finset.getBodyRadius();
|
||||
|
||||
// Translate & rotate the coordinates
|
||||
for (int i=0; i<finPoints.length; i++) {
|
||||
finPoints[i] = cantRotation.transform(finPoints[i]);
|
||||
finPoints[i] = baseRotation.transform(finPoints[i].add(0,radius,0));
|
||||
}
|
||||
|
||||
Transformation cantRotation = finset.getCantRotation();
|
||||
finPoints = cantRotation.transform(finPoints);
|
||||
finPoints = transformation.transform(finPoints);
|
||||
|
||||
// Generate shapes
|
||||
RocketComponentShape[] finShape = new RocketComponentShape[ finCount];
|
||||
for (int finNum=0; finNum<finCount; finNum++) {
|
||||
Coordinate a;
|
||||
Path2D.Float p;
|
||||
|
||||
Path2D.Float p;
|
||||
{
|
||||
// Make polygon
|
||||
p = new Path2D.Float();
|
||||
for (int i=0; i<finPoints.length; i++) {
|
||||
// previous version
|
||||
// a = transformation.transform(finset.toAbsolute(finPoints[i])[0]);
|
||||
a = transformation.transform(finSetFront.add(finPoints[i]));
|
||||
Coordinate c = finSetFront.add(finPoints[i]);
|
||||
|
||||
if (i==0)
|
||||
p.moveTo(a.x*S, a.y*S);
|
||||
p.moveTo(c.x*S, c.y*S);
|
||||
else
|
||||
p.lineTo(a.x*S, a.y*S);
|
||||
p.lineTo(c.x*S, c.y*S);
|
||||
}
|
||||
|
||||
p.closePath();
|
||||
finShape[finNum] = new RocketComponentShape( p, finset);
|
||||
|
||||
// Rotate fin coordinates
|
||||
for (int i=0; i<finPoints.length; i++)
|
||||
finPoints[i] = finRotation.transform(finPoints[i]);
|
||||
}
|
||||
|
||||
return finShape;
|
||||
return new RocketComponentShape[] {new RocketComponentShape(p, finset)};
|
||||
}
|
||||
|
||||
public static RocketComponentShape[] getShapesBack(
|
||||
@ -73,7 +51,7 @@ public class FinSetShapes extends RocketComponentShape {
|
||||
Coordinate location) {
|
||||
|
||||
net.sf.openrocket.rocketcomponent.FinSet finset = (net.sf.openrocket.rocketcomponent.FinSet)component;
|
||||
|
||||
|
||||
Shape[] toReturn;
|
||||
|
||||
if (MathUtil.equals(finset.getCantAngle(),0)){
|
||||
@ -89,51 +67,38 @@ public class FinSetShapes extends RocketComponentShape {
|
||||
|
||||
private static Shape[] uncantedShapesBack(net.sf.openrocket.rocketcomponent.FinSet finset,
|
||||
Transformation transformation,
|
||||
Coordinate location) {
|
||||
Coordinate finFront) {
|
||||
|
||||
int fins = finset.getFinCount();
|
||||
double radius = finset.getBodyRadius();
|
||||
double thickness = finset.getThickness();
|
||||
double height = finset.getSpan();
|
||||
Coordinate compCenter = location;
|
||||
Transformation baseRotation = Transformation.rotate_x( finset.getAngularOffset());
|
||||
Transformation finRotation = finset.getFinRotationTransformation();
|
||||
|
||||
|
||||
// Generate base coordinates for a single fin
|
||||
Coordinate c[] = new Coordinate[4];
|
||||
c[0]=new Coordinate(0,radius,-thickness/2);
|
||||
c[1]=new Coordinate(0,radius,thickness/2);
|
||||
c[2]=new Coordinate(0,height+radius,thickness/2);
|
||||
c[3]=new Coordinate(0,height+radius,-thickness/2);
|
||||
c[0]=new Coordinate(0, 0,-thickness/2);
|
||||
c[1]=new Coordinate(0, 0,thickness/2);
|
||||
c[2]=new Coordinate(0,height,thickness/2);
|
||||
c[3]=new Coordinate(0,height,-thickness/2);
|
||||
|
||||
System.err.println(String.format(" -- %s", transformation.toString() ));
|
||||
|
||||
// Apply base rotation
|
||||
transformPoints(c,baseRotation);
|
||||
c = transformation.transform(c);
|
||||
|
||||
// Make polygon
|
||||
Coordinate a;
|
||||
Path2D.Double p = new Path2D.Double();
|
||||
|
||||
// Generate shapes
|
||||
Shape[] s = new Shape[fins];
|
||||
for (int fin=0; fin<fins; fin++) {
|
||||
Coordinate a;
|
||||
Path2D.Double p;
|
||||
|
||||
// Make polygon
|
||||
p = new Path2D.Double();
|
||||
a = transformation.transform(compCenter.add( c[0] ));
|
||||
p.moveTo(a.z*S, a.y*S);
|
||||
a = transformation.transform(compCenter.add( c[1] ));
|
||||
p.lineTo(a.z*S, a.y*S);
|
||||
a = transformation.transform(compCenter.add( c[2] ));
|
||||
p.lineTo(a.z*S, a.y*S);
|
||||
a = transformation.transform(compCenter.add( c[3] ));
|
||||
p.lineTo(a.z*S, a.y*S);
|
||||
p.closePath();
|
||||
s[fin] = p;
|
||||
|
||||
// Rotate fin coordinates
|
||||
transformPoints(c,finRotation);
|
||||
}
|
||||
a = finFront.add( c[0] );
|
||||
p.moveTo(a.z*S, a.y*S);
|
||||
a = finFront.add( c[1] );
|
||||
p.lineTo(a.z*S, a.y*S);
|
||||
a = finFront.add( c[2] );
|
||||
p.lineTo(a.z*S, a.y*S);
|
||||
a = finFront.add( c[3] );
|
||||
p.lineTo(a.z*S, a.y*S);
|
||||
p.closePath();
|
||||
|
||||
return s;
|
||||
return new Shape[]{p};
|
||||
}
|
||||
|
||||
|
||||
@ -143,11 +108,9 @@ public class FinSetShapes extends RocketComponentShape {
|
||||
Coordinate location) {
|
||||
int i;
|
||||
int fins = finset.getFinCount();
|
||||
double radius = finset.getBodyRadius();
|
||||
// double radius = finset.getBodyRadius();
|
||||
double thickness = finset.getThickness();
|
||||
|
||||
Transformation baseRotation = Transformation.rotate_x( finset.getAngularOffset());
|
||||
Transformation finRotation = finset.getFinRotationTransformation();
|
||||
Transformation cantRotation = finset.getCantRotation();
|
||||
|
||||
Coordinate[] sidePoints;
|
||||
@ -160,9 +123,9 @@ public class FinSetShapes extends RocketComponentShape {
|
||||
break;
|
||||
}
|
||||
|
||||
transformPoints(points,cantRotation);
|
||||
transformPoints(points,new Transformation(0,radius,0));
|
||||
transformPoints(points,baseRotation);
|
||||
points = cantRotation.transform( points );
|
||||
// transformPoints(points,new Transformation(0,radius,0));
|
||||
points = transformation.transform( points );
|
||||
|
||||
|
||||
sidePoints = new Coordinate[points.length];
|
||||
@ -197,10 +160,6 @@ public class FinSetShapes extends RocketComponentShape {
|
||||
|
||||
s[2*fin] = makePolygonBack(sidePoints,finset,transformation, location);
|
||||
s[2*fin+1] = makePolygonBack(backPoints,finset,transformation, location);
|
||||
|
||||
// Rotate fin coordinates
|
||||
transformPoints(sidePoints,finRotation);
|
||||
transformPoints(backPoints,finRotation);
|
||||
}
|
||||
|
||||
} else {
|
||||
@ -208,7 +167,6 @@ public class FinSetShapes extends RocketComponentShape {
|
||||
s = new Shape[fins];
|
||||
for (int fin=0; fin<fins; fin++) {
|
||||
s[fin] = makePolygonBack(sidePoints,finset,transformation, location);
|
||||
transformPoints(sidePoints,finRotation);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@ -1,52 +1,42 @@
|
||||
package net.sf.openrocket.gui.rocketfigure;
|
||||
|
||||
import java.awt.Shape;
|
||||
import java.awt.geom.Ellipse2D;
|
||||
import java.awt.geom.Rectangle2D;
|
||||
|
||||
import net.sf.openrocket.util.Coordinate;
|
||||
import net.sf.openrocket.util.Transformation;
|
||||
|
||||
import net.sf.openrocket.rocketcomponent.LaunchLug;
|
||||
import net.sf.openrocket.rocketcomponent.RocketComponent;
|
||||
|
||||
public class LaunchLugShapes extends RocketComponentShape {
|
||||
|
||||
public static RocketComponentShape[] getShapesSide(
|
||||
net.sf.openrocket.rocketcomponent.RocketComponent component,
|
||||
RocketComponent component,
|
||||
Transformation transformation,
|
||||
Coordinate componentAbsoluteLocation) {
|
||||
Coordinate instanceAbsoluteLocation) {
|
||||
|
||||
net.sf.openrocket.rocketcomponent.LaunchLug lug = (net.sf.openrocket.rocketcomponent.LaunchLug)component;
|
||||
|
||||
double length = lug.getLength();
|
||||
LaunchLug lug = (LaunchLug)component;
|
||||
double length = lug.getLength();
|
||||
double radius = lug.getOuterRadius();
|
||||
Coordinate[] start = transformation.transform( lug.getLocations());
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
return RocketComponentShape.toArray(s, component);
|
||||
Shape[] s = new Shape[]{
|
||||
TubeShapes.getShapesSide( transformation, instanceAbsoluteLocation, length, radius )
|
||||
};
|
||||
|
||||
return RocketComponentShape.toArray(s, component);
|
||||
}
|
||||
|
||||
|
||||
public static RocketComponentShape[] getShapesBack(
|
||||
net.sf.openrocket.rocketcomponent.RocketComponent component,
|
||||
RocketComponent component,
|
||||
Transformation transformation,
|
||||
Coordinate instanceOffset) {
|
||||
Coordinate instanceAbsoluteLocation) {
|
||||
|
||||
net.sf.openrocket.rocketcomponent.LaunchLug lug = (net.sf.openrocket.rocketcomponent.LaunchLug)component;
|
||||
|
||||
double or = lug.getOuterRadius();
|
||||
|
||||
Coordinate[] start = transformation.transform( lug.getLocations());
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
LaunchLug lug = (LaunchLug)component;
|
||||
double radius = lug.getOuterRadius();
|
||||
|
||||
Shape[] s = new Shape[]{TubeShapes.getShapesBack( transformation, instanceAbsoluteLocation, radius)};
|
||||
|
||||
return RocketComponentShape.toArray(s, component);
|
||||
}
|
||||
}
|
||||
|
||||
@ -6,6 +6,8 @@ import java.awt.geom.Line2D;
|
||||
import java.awt.geom.Path2D;
|
||||
import java.awt.geom.Point2D;
|
||||
|
||||
import net.sf.openrocket.rocketcomponent.RailButton;
|
||||
import net.sf.openrocket.rocketcomponent.RocketComponent;
|
||||
import net.sf.openrocket.util.Coordinate;
|
||||
import net.sf.openrocket.util.Transformation;
|
||||
|
||||
@ -13,11 +15,11 @@ import net.sf.openrocket.util.Transformation;
|
||||
public class RailButtonShapes extends RocketComponentShape {
|
||||
|
||||
public static RocketComponentShape[] getShapesSide(
|
||||
net.sf.openrocket.rocketcomponent.RocketComponent component,
|
||||
RocketComponent component,
|
||||
Transformation transformation,
|
||||
Coordinate componentAbsoluteLocation) {
|
||||
Coordinate instanceAbsoluteLocation) {
|
||||
|
||||
net.sf.openrocket.rocketcomponent.RailButton btn = (net.sf.openrocket.rocketcomponent.RailButton)component;
|
||||
RailButton btn = (RailButton)component;
|
||||
|
||||
final double rotation_rad = btn.getAngularOffset();
|
||||
final double baseHeight = btn.getStandoff();
|
||||
@ -27,9 +29,6 @@ public class RailButtonShapes extends RocketComponentShape {
|
||||
final double outerRadius = outerDiameter/2;
|
||||
final double innerDiameter = btn.getInnerDiameter();
|
||||
final double innerRadius = innerDiameter/2;
|
||||
Coordinate[] inst = transformation.transform( btn.getLocations());
|
||||
|
||||
Shape[] s = new Shape[inst.length];
|
||||
|
||||
final double sinr = Math.abs(Math.sin(rotation_rad));
|
||||
final double cosr = Math.cos(rotation_rad);
|
||||
@ -38,49 +37,46 @@ public class RailButtonShapes extends RocketComponentShape {
|
||||
final double flangeHeightcos = flangeHeight*cosr;
|
||||
|
||||
|
||||
for (int i=0; i < inst.length; i++) {
|
||||
Path2D.Double compound = new Path2D.Double();
|
||||
s[i] = compound;
|
||||
{// base
|
||||
final double drawWidth = outerDiameter;
|
||||
final double drawHeight = outerDiameter*sinr;
|
||||
final Point2D.Double center = new Point2D.Double( inst[i].x, inst[i].y);
|
||||
Point2D.Double lowerLeft = new Point2D.Double( center.x - outerRadius, center.y-outerRadius*sinr);
|
||||
compound.append( new Ellipse2D.Double( lowerLeft.x*S, lowerLeft.y*S, drawWidth*S, drawHeight*S), false);
|
||||
|
||||
compound.append( new Line2D.Double( lowerLeft.x*S, center.y*S, lowerLeft.x*S, (center.y+baseHeightcos)*S ), false);
|
||||
compound.append( new Line2D.Double( (center.x+outerRadius)*S, center.y*S, (center.x+outerRadius)*S, (center.y+baseHeightcos)*S ), false);
|
||||
|
||||
compound.append( new Ellipse2D.Double( lowerLeft.x*S, (lowerLeft.y+baseHeightcos)*S, drawWidth*S, drawHeight*S), false);
|
||||
}
|
||||
Path2D.Double path = new Path2D.Double();
|
||||
{// central pillar
|
||||
final double drawWidth = outerDiameter;
|
||||
final double drawHeight = outerDiameter*sinr;
|
||||
final Point2D.Double center = new Point2D.Double( instanceAbsoluteLocation.x, instanceAbsoluteLocation.y );
|
||||
Point2D.Double lowerLeft = new Point2D.Double( center.x - outerRadius, center.y-outerRadius*sinr);
|
||||
path.append( new Ellipse2D.Double( lowerLeft.x*S, lowerLeft.y*S, drawWidth*S, drawHeight*S), false);
|
||||
|
||||
{// inner
|
||||
final double drawWidth = innerDiameter;
|
||||
final double drawHeight = innerDiameter*sinr;
|
||||
final Point2D.Double center = new Point2D.Double( inst[i].x, inst[i].y+baseHeightcos);
|
||||
final Point2D.Double lowerLeft = new Point2D.Double( center.x - innerRadius, center.y-innerRadius*sinr);
|
||||
compound.append( new Ellipse2D.Double( lowerLeft.x*S, lowerLeft.y*S, drawWidth*S, drawHeight*S), false);
|
||||
|
||||
compound.append( new Line2D.Double( lowerLeft.x*S, center.y*S, lowerLeft.x*S, (center.y+innerHeightcos)*S ), false);
|
||||
compound.append( new Line2D.Double( (center.x+innerRadius)*S, center.y*S, (center.x+innerRadius)*S, (center.y+innerHeightcos)*S ), false);
|
||||
|
||||
compound.append( new Ellipse2D.Double( lowerLeft.x*S, (lowerLeft.y+innerHeightcos)*S, drawWidth*S, drawHeight*S), false);
|
||||
}
|
||||
{// outer flange
|
||||
final double drawWidth = outerDiameter;
|
||||
final double drawHeight = outerDiameter*sinr;
|
||||
final Point2D.Double center = new Point2D.Double( inst[i].x, inst[i].y+(baseHeightcos+innerHeightcos));
|
||||
final Point2D.Double lowerLeft = new Point2D.Double( center.x - outerRadius, center.y-outerRadius*sinr);
|
||||
compound.append( new Ellipse2D.Double( lowerLeft.x*S, lowerLeft.y*S, drawWidth*S, drawHeight*S), false);
|
||||
|
||||
compound.append( new Line2D.Double( lowerLeft.x*S, center.y*S, lowerLeft.x*S, (center.y+flangeHeightcos)*S ), false);
|
||||
compound.append( new Line2D.Double( (center.x+outerRadius)*S, center.y*S, (center.x+outerRadius)*S, (center.y+flangeHeightcos)*S ), false);
|
||||
|
||||
compound.append( new Ellipse2D.Double( lowerLeft.x*S, (lowerLeft.y+flangeHeightcos)*S, drawWidth*S, drawHeight*S), false);
|
||||
}
|
||||
path.append( new Line2D.Double( lowerLeft.x*S, center.y*S, lowerLeft.x*S, (center.y+baseHeightcos)*S ), false);
|
||||
path.append( new Line2D.Double( (center.x+outerRadius)*S, center.y*S, (center.x+outerRadius)*S, (center.y+baseHeightcos)*S ), false);
|
||||
|
||||
path.append( new Ellipse2D.Double( lowerLeft.x*S, (lowerLeft.y+baseHeightcos)*S, drawWidth*S, drawHeight*S), false);
|
||||
}
|
||||
|
||||
{// inner
|
||||
final double drawWidth = innerDiameter;
|
||||
final double drawHeight = innerDiameter*sinr;
|
||||
final Point2D.Double center = new Point2D.Double( instanceAbsoluteLocation.x, instanceAbsoluteLocation.y + baseHeightcos);
|
||||
final Point2D.Double lowerLeft = new Point2D.Double( center.x - innerRadius, center.y-innerRadius*sinr);
|
||||
path.append( new Ellipse2D.Double( lowerLeft.x*S, lowerLeft.y*S, drawWidth*S, drawHeight*S), false);
|
||||
|
||||
path.append( new Line2D.Double( lowerLeft.x*S, center.y*S, lowerLeft.x*S, (center.y+innerHeightcos)*S ), false);
|
||||
path.append( new Line2D.Double( (center.x+innerRadius)*S, center.y*S, (center.x+innerRadius)*S, (center.y+innerHeightcos)*S ), false);
|
||||
|
||||
path.append( new Ellipse2D.Double( lowerLeft.x*S, (lowerLeft.y+innerHeightcos)*S, drawWidth*S, drawHeight*S), false);
|
||||
}
|
||||
{// outer flange
|
||||
final double drawWidth = outerDiameter;
|
||||
final double drawHeight = outerDiameter*sinr;
|
||||
final Point2D.Double center = new Point2D.Double( instanceAbsoluteLocation.x, instanceAbsoluteLocation.y+baseHeightcos+innerHeightcos);
|
||||
final Point2D.Double lowerLeft = new Point2D.Double( center.x - outerRadius, center.y-outerRadius*sinr);
|
||||
path.append( new Ellipse2D.Double( lowerLeft.x*S, lowerLeft.y*S, drawWidth*S, drawHeight*S), false);
|
||||
|
||||
path.append( new Line2D.Double( lowerLeft.x*S, center.y*S, lowerLeft.x*S, (center.y+flangeHeightcos)*S ), false);
|
||||
path.append( new Line2D.Double( (center.x+outerRadius)*S, center.y*S, (center.x+outerRadius)*S, (center.y+flangeHeightcos)*S ), false);
|
||||
|
||||
path.append( new Ellipse2D.Double( lowerLeft.x*S, (lowerLeft.y+flangeHeightcos)*S, drawWidth*S, drawHeight*S), false);
|
||||
}
|
||||
|
||||
return RocketComponentShape.toArray(s, component);
|
||||
return RocketComponentShape.toArray( new Shape[]{ path }, component );
|
||||
}
|
||||
|
||||
|
||||
|
||||
@ -14,39 +14,26 @@ public class RingComponentShapes extends RocketComponentShape {
|
||||
public static RocketComponentShape[] getShapesSide(
|
||||
net.sf.openrocket.rocketcomponent.RocketComponent component,
|
||||
Transformation transformation,
|
||||
Coordinate componentAbsoluteLocation) {
|
||||
Coordinate instanceAbsoluteLocation) {
|
||||
|
||||
net.sf.openrocket.rocketcomponent.RingComponent tube = (net.sf.openrocket.rocketcomponent.RingComponent)component;
|
||||
Shape[] s;
|
||||
|
||||
double length = tube.getLength();
|
||||
double or = tube.getOuterRadius();
|
||||
double ir = tube.getInnerRadius();
|
||||
double outerRadius = tube.getOuterRadius();
|
||||
double innerRadius = tube.getInnerRadius();
|
||||
|
||||
// old version
|
||||
//Coordinate[] instanceOffsets = new Coordinate[]{ transformation.transform( componentAbsoluteLocation )};
|
||||
//instanceOffsets = component.shiftCoordinates(instanceOffsets);
|
||||
|
||||
// new version
|
||||
Coordinate[] instanceOffsets = transformation.transform( component.getLocations());
|
||||
|
||||
|
||||
if ((or-ir >= 0.0012) && (ir > 0)) {
|
||||
if ((outerRadius-innerRadius >= 0.0012) && (innerRadius > 0)) {
|
||||
// Draw outer and inner
|
||||
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(instanceOffsets[i].x*S,(instanceOffsets[i].y-ir)*S,
|
||||
length*S,2*ir*S);
|
||||
}
|
||||
s = new Shape[] {
|
||||
TubeShapes.getShapesSide(transformation, instanceAbsoluteLocation, length, outerRadius),
|
||||
TubeShapes.getShapesSide(transformation, instanceAbsoluteLocation, length, innerRadius)
|
||||
};
|
||||
} else {
|
||||
// Draw only outer
|
||||
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);
|
||||
}
|
||||
s = new Shape[] {
|
||||
TubeShapes.getShapesSide(transformation, instanceAbsoluteLocation, length, outerRadius)
|
||||
};
|
||||
}
|
||||
return RocketComponentShape.toArray( s, component);
|
||||
}
|
||||
@ -55,37 +42,24 @@ public class RingComponentShapes extends RocketComponentShape {
|
||||
public static RocketComponentShape[] getShapesBack(
|
||||
net.sf.openrocket.rocketcomponent.RocketComponent component,
|
||||
Transformation transformation,
|
||||
Coordinate componentAbsoluteLocation) {
|
||||
Coordinate instanceAbsoluteLocation) {
|
||||
net.sf.openrocket.rocketcomponent.RingComponent tube = (net.sf.openrocket.rocketcomponent.RingComponent)component;
|
||||
Shape[] s;
|
||||
|
||||
double or = tube.getOuterRadius();
|
||||
double ir = tube.getInnerRadius();
|
||||
|
||||
Coordinate[] instanceOffsets = new Coordinate[]{ transformation.transform( componentAbsoluteLocation )};
|
||||
double outerRadius = tube.getOuterRadius();
|
||||
double innerRadius = tube.getInnerRadius();
|
||||
|
||||
if ((outerRadius-innerRadius >= 0.0012) && (innerRadius > 0)) {
|
||||
s = new Shape[] {
|
||||
TubeShapes.getShapesBack(transformation, instanceAbsoluteLocation, outerRadius),
|
||||
TubeShapes.getShapesBack(transformation, instanceAbsoluteLocation, innerRadius)
|
||||
};
|
||||
}else {
|
||||
s = new Shape[] {
|
||||
TubeShapes.getShapesBack(transformation, instanceAbsoluteLocation, outerRadius)
|
||||
};
|
||||
}
|
||||
|
||||
// old version
|
||||
//instanceOffsets = component.shiftCoordinates(instanceOffsets);
|
||||
|
||||
// new version
|
||||
instanceOffsets = component.getLocations();
|
||||
|
||||
if ((ir < or) && (ir > 0)) {
|
||||
// Draw inner and outer
|
||||
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((instanceOffsets[i].z-ir)*S, (instanceOffsets[i].y-ir)*S,
|
||||
2*ir*S, 2*ir*S);
|
||||
}
|
||||
} else {
|
||||
// Draw only outer
|
||||
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);
|
||||
}
|
||||
|
||||
|
||||
@ -1,5 +1,6 @@
|
||||
package net.sf.openrocket.gui.rocketfigure;
|
||||
|
||||
import net.sf.openrocket.rocketcomponent.RocketComponent;
|
||||
import net.sf.openrocket.rocketcomponent.Transition;
|
||||
import net.sf.openrocket.util.Coordinate;
|
||||
import net.sf.openrocket.util.Transformation;
|
||||
@ -17,21 +18,21 @@ public class TransitionShapes extends RocketComponentShape {
|
||||
public static RocketComponentShape[] getShapesSide(
|
||||
net.sf.openrocket.rocketcomponent.RocketComponent component,
|
||||
Transformation transformation,
|
||||
Coordinate instanceOffset) {
|
||||
return getShapesSide(component, transformation, instanceOffset, S);
|
||||
Coordinate instanceLocation) {
|
||||
return getShapesSide(component, transformation, instanceLocation, S);
|
||||
}
|
||||
|
||||
public static RocketComponentShape[] getShapesSide(
|
||||
net.sf.openrocket.rocketcomponent.RocketComponent component,
|
||||
RocketComponent component,
|
||||
Transformation transformation,
|
||||
Coordinate componentAbsoluteLocation,
|
||||
Coordinate instanceAbsoluteLocation,
|
||||
final double scaleFactor) {
|
||||
net.sf.openrocket.rocketcomponent.Transition transition = (net.sf.openrocket.rocketcomponent.Transition)component;
|
||||
|
||||
Transition transition = (Transition)component;
|
||||
|
||||
RocketComponentShape[] mainShapes;
|
||||
|
||||
Coordinate frontCenter = transformation.transform( componentAbsoluteLocation );
|
||||
// this component type does not allow multiple instances
|
||||
Coordinate frontCenter = instanceAbsoluteLocation;
|
||||
|
||||
// Simpler shape for conical transition, others use the method from SymmetricComponent
|
||||
if (transition.getType() == Transition.Shape.CONICAL) {
|
||||
@ -48,14 +49,14 @@ public class TransitionShapes extends RocketComponentShape {
|
||||
|
||||
mainShapes = new RocketComponentShape[] { new RocketComponentShape( path, component) };
|
||||
} else {
|
||||
mainShapes = SymmetricComponentShapes.getShapesSide(component, transformation, componentAbsoluteLocation, scaleFactor);
|
||||
mainShapes = SymmetricComponentShapes.getShapesSide(component, transformation, instanceAbsoluteLocation, scaleFactor);
|
||||
}
|
||||
|
||||
Rectangle2D.Double foreShoulder=null, aftShoulder=null;
|
||||
int arrayLength = mainShapes.length;
|
||||
|
||||
if (transition.getForeShoulderLength() > 0.0005) {
|
||||
Coordinate foreTransitionShoulderCenter = componentAbsoluteLocation.sub( transition.getForeShoulderLength()/2, 0, 0);
|
||||
Coordinate foreTransitionShoulderCenter = instanceAbsoluteLocation.sub( transition.getForeShoulderLength()/2, 0, 0);
|
||||
frontCenter = transformation.transform( foreTransitionShoulderCenter);
|
||||
|
||||
double rad = transition.getForeShoulderRadius();
|
||||
@ -64,7 +65,7 @@ public class TransitionShapes extends RocketComponentShape {
|
||||
arrayLength++;
|
||||
}
|
||||
if (transition.getAftShoulderLength() > 0.0005) {
|
||||
Coordinate aftTransitionShoulderCenter = componentAbsoluteLocation.add( transition.getLength() + (transition.getAftShoulderLength())/2, 0, 0);
|
||||
Coordinate aftTransitionShoulderCenter = instanceAbsoluteLocation.add( transition.getLength() + (transition.getAftShoulderLength())/2, 0, 0);
|
||||
frontCenter= transformation.transform( aftTransitionShoulderCenter );
|
||||
|
||||
double rad = transition.getAftShoulderRadius();
|
||||
|
||||
33
swing/src/net/sf/openrocket/gui/rocketfigure/TubeShapes.java
Normal file
33
swing/src/net/sf/openrocket/gui/rocketfigure/TubeShapes.java
Normal file
@ -0,0 +1,33 @@
|
||||
package net.sf.openrocket.gui.rocketfigure;
|
||||
|
||||
import java.awt.Shape;
|
||||
import java.awt.geom.Ellipse2D;
|
||||
import java.awt.geom.Rectangle2D;
|
||||
|
||||
import net.sf.openrocket.util.Coordinate;
|
||||
import net.sf.openrocket.util.Transformation;
|
||||
|
||||
|
||||
public class TubeShapes extends RocketComponentShape {
|
||||
|
||||
public static Shape getShapesSide(
|
||||
Transformation transformation,
|
||||
Coordinate instanceAbsoluteLocation,
|
||||
final double length, final double radius ){
|
||||
|
||||
return new Rectangle2D.Double((instanceAbsoluteLocation.x)*S, //x - the X coordinate of the upper-left corner of the newly constructed Rectangle2D
|
||||
(instanceAbsoluteLocation.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
|
||||
}
|
||||
|
||||
public static Shape getShapesBack(
|
||||
Transformation transformation,
|
||||
Coordinate instanceAbsoluteLocation,
|
||||
final double radius ) {
|
||||
|
||||
return new Ellipse2D.Double((instanceAbsoluteLocation.z-radius)*S, (instanceAbsoluteLocation.y-radius)*S, 2*radius*S, 2*radius*S);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@ -183,9 +183,9 @@ public class RocketFigure extends AbstractScaleFigure {
|
||||
figureShapes.clear();
|
||||
|
||||
calculateSize();
|
||||
FlightConfiguration config = rocket.getSelectedConfiguration();
|
||||
getShapes( figureShapes, config);
|
||||
|
||||
getShapeTree( this.figureShapes, rocket, this.transformation, Coordinate.ZERO);
|
||||
|
||||
repaint();
|
||||
fireChangeEvent();
|
||||
}
|
||||
@ -347,23 +347,23 @@ public class RocketFigure extends AbstractScaleFigure {
|
||||
|
||||
// <component>.getLocation() will return all the parent instances of this owning component, AND all of it's own instances as well.
|
||||
// so, just draw a motor once for each Coordinate returned...
|
||||
Coordinate[] mountLocations = mountComponent.getLocations();
|
||||
Coordinate[] mountLocations = mount.getLocations();
|
||||
|
||||
double mountLength = mountComponent.getLength();
|
||||
//System.err.println("Drawing motor from here. Motor: "+motor.getDesignation()+" of length: "+motor.getLength());
|
||||
// System.err.println("Drawing Motor: "+motor.getDesignation()+" (x"+mountLocations.length+")");
|
||||
for ( Coordinate curMountLocation : mountLocations ){
|
||||
Coordinate curMotorLocation = curMountLocation.add( mountLength - motorLength + mount.getMotorOverhang(), 0, 0);
|
||||
|
||||
Coordinate coord = curMotorLocation;
|
||||
Coordinate curMotorLocation = curMountLocation.add( mountLength - motorLength + mount.getMotorOverhang(), 0, 0);
|
||||
// System.err.println(String.format(" mount instance: %s => %s", curMountLocation.toString(), curMotorLocation.toString() ));
|
||||
|
||||
{
|
||||
Shape s;
|
||||
if (currentViewType == RocketPanel.VIEW_TYPE.SideView) {
|
||||
s = new Rectangle2D.Double(EXTRA_SCALE * coord.x,
|
||||
EXTRA_SCALE * (coord.y - motorRadius), EXTRA_SCALE * motorLength,
|
||||
s = new Rectangle2D.Double(EXTRA_SCALE * curMotorLocation.x,
|
||||
EXTRA_SCALE * (curMotorLocation.y - motorRadius), EXTRA_SCALE * motorLength,
|
||||
EXTRA_SCALE * 2 * motorRadius);
|
||||
} else {
|
||||
s = new Ellipse2D.Double(EXTRA_SCALE * (coord.z - motorRadius),
|
||||
EXTRA_SCALE * (coord.y - motorRadius), EXTRA_SCALE * 2 * motorRadius,
|
||||
s = new Ellipse2D.Double(EXTRA_SCALE * (curMotorLocation.z - motorRadius),
|
||||
EXTRA_SCALE * (curMotorLocation.y - motorRadius), EXTRA_SCALE * 2 * motorRadius,
|
||||
EXTRA_SCALE * 2 * motorRadius);
|
||||
}
|
||||
g2.setColor(fillColor);
|
||||
@ -420,41 +420,52 @@ public class RocketFigure extends AbstractScaleFigure {
|
||||
return l.toArray(new RocketComponent[0]);
|
||||
}
|
||||
|
||||
// facade for the recursive function below
|
||||
private void getShapes(ArrayList<RocketComponentShape> allShapes, FlightConfiguration configuration){
|
||||
for( AxialStage stage : configuration.getActiveStages()){
|
||||
getShapeTree( allShapes, stage, Coordinate.ZERO);
|
||||
}
|
||||
}
|
||||
|
||||
// NOTE: Recursive function
|
||||
private void getShapeTree(
|
||||
ArrayList<RocketComponentShape> allShapes, // output parameter
|
||||
final RocketComponent comp,
|
||||
final Coordinate parentLocation){
|
||||
|
||||
RocketPanel.VIEW_TYPE viewType = this.currentViewType;
|
||||
Transformation viewTransform = this.transformation;
|
||||
Coordinate[] locs = comp.getLocations();
|
||||
|
||||
// generate shapes
|
||||
for( Coordinate curLocation : locs){
|
||||
allShapes = addThisShape( allShapes, viewType, comp, curLocation, viewTransform);
|
||||
}
|
||||
ArrayList<RocketComponentShape> allShapes, // output parameter
|
||||
final RocketComponent comp,
|
||||
final Transformation parentTransform,
|
||||
final Coordinate parentLocation){
|
||||
|
||||
// recurse into component's children
|
||||
for( RocketComponent child: comp.getChildren() ){
|
||||
if( child instanceof AxialStage ){
|
||||
// recursing into BoosterSet here would double count its tree
|
||||
continue;
|
||||
}
|
||||
|
||||
for( Coordinate curLocation : locs){
|
||||
getShapeTree( allShapes, child, curLocation);
|
||||
}
|
||||
}
|
||||
|
||||
return;
|
||||
final int instanceCount = comp.getInstanceCount();
|
||||
Coordinate[] instanceLocations = comp.getInstanceLocations();
|
||||
instanceLocations = parentTransform.transform( instanceLocations );
|
||||
double[] instanceAngles = comp.getInstanceAngles();
|
||||
if( instanceLocations.length != instanceAngles.length ){
|
||||
throw new ArrayIndexOutOfBoundsException(String.format("lengths of location array (%d) and angle arrays (%d) differs! (in: %s) ", instanceLocations.length, instanceAngles.length, comp.getName()));
|
||||
}
|
||||
|
||||
// iterate over the aggregated instances *for the whole* tree.
|
||||
for( int index = 0; instanceCount > index ; ++index ){
|
||||
final double currentAngle = instanceAngles[index];
|
||||
|
||||
Transformation currentTransform = parentTransform;
|
||||
if( 0.00001 < Math.abs( currentAngle )) {
|
||||
Transformation currentAngleTransform = Transformation.rotate_x( currentAngle );
|
||||
currentTransform = currentAngleTransform.applyTransformation( parentTransform );
|
||||
}
|
||||
|
||||
Coordinate currentLocation = parentLocation.add( instanceLocations[index] );
|
||||
|
||||
// System.err.println(String.format("@%s: %s -- inst: [%d/%d]", comp.getClass().getSimpleName(), comp.getName(), index+1, instanceCount));
|
||||
// System.err.println(String.format(" -- stage: %d, active: %b, config: (%d) %s", comp.getStageNumber(), this.getConfiguration().isComponentActive(comp), this.getConfiguration().instanceNumber, this.getConfiguration().getId()));
|
||||
// System.err.println(String.format(" -- %s + %s = %s", parentLocation.toString(), instanceLocations[index].toString(), currentLocation.toString()));
|
||||
// if( 0.00001 < Math.abs( currentAngle )) {
|
||||
// System.err.println(String.format(" -- at: %6.4f radians", currentAngle));
|
||||
// }
|
||||
|
||||
// generate shape for this component, if active
|
||||
if( this.getConfiguration().isComponentActive( comp )){
|
||||
allShapes = addThisShape( allShapes, this.currentViewType, comp, currentLocation, currentTransform);
|
||||
}
|
||||
|
||||
// recurse into component's children
|
||||
for( RocketComponent child: comp.getChildren() ){
|
||||
// draw a tree for each instance subcomponent
|
||||
getShapeTree( allShapes, child, currentTransform, currentLocation );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user