[Large] Refactored RocketFigure drawing code to enable moving components by offset

This commit is contained in:
Daniel_M_Williams 2015-06-25 11:22:58 -04:00
parent 5e96288896
commit 56dec21824
18 changed files with 427 additions and 196 deletions

View File

@ -0,0 +1,24 @@
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();
}

View File

@ -2,11 +2,12 @@ package net.sf.openrocket.rocketcomponent;
import net.sf.openrocket.l10n.Translator;
import net.sf.openrocket.startup.Application;
import net.sf.openrocket.util.Coordinate;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class Stage extends ComponentAssembly implements FlightConfigurableComponent, OutsideComponent {
public class Stage extends ComponentAssembly implements FlightConfigurableComponent, MultipleComponent, OutsideComponent {
static final Translator trans = Application.getTranslator();
private static final Logger log = LoggerFactory.getLogger(Stage.class);
@ -18,8 +19,8 @@ public class Stage extends ComponentAssembly implements FlightConfigurableCompon
private double radialPosition_m = 0;
private double rotation_rad = 0;
private int count = 2;
private double separationAngle = Math.PI;
private int count = 1;
private double angularSeparation = Math.PI;
public Stage() {
@ -84,9 +85,12 @@ public class Stage extends ComponentAssembly implements FlightConfigurableCompon
this.relativePosition = Position.BOTTOM;
this.position = 0;
}
if (this.outside) {
fireComponentChangeEvent(ComponentChangeEvent.BOTH_CHANGE);
if (!this.outside) {
this.count = 1;
}
fireComponentChangeEvent(ComponentChangeEvent.BOTH_CHANGE);
}
@Override
@ -98,7 +102,7 @@ public class Stage extends ComponentAssembly implements FlightConfigurableCompon
public void setCount(final int _count) {
mutex.verify();
this.count = _count;
this.separationAngle = Math.PI * 2 / this.count;
this.angularSeparation = Math.PI * 2 / this.count;
if (this.outside) {
fireComponentChangeEvent(ComponentChangeEvent.BOTH_CHANGE);
@ -183,7 +187,26 @@ public class Stage extends ComponentAssembly implements FlightConfigurableCompon
}
}
@Override
public int getInstanceCount() {
return this.count;
}
@Override
public Coordinate[] getInstanceOffsets() {
Coordinate[] toReturn = new Coordinate[this.count];
double radius = this.radialPosition_m;
double angle0 = this.angularPosition_rad;
double angleIncr = this.angularSeparation;
double thisAngle = angle0;
for (int instanceNumber = 0; instanceNumber < this.count; instanceNumber++) {
toReturn[instanceNumber] = new Coordinate(0, radius * Math.cos(thisAngle), radius * Math.sin(thisAngle));
thisAngle += angleIncr;
}
return toReturn;
}
}

View File

@ -1,8 +1,10 @@
package net.sf.openrocket.gui.print;
import net.sf.openrocket.gui.print.visitor.PageFitPrintStrategy;
import net.sf.openrocket.gui.rocketfigure.RocketComponentShape;
import net.sf.openrocket.gui.rocketfigure.TransitionShapes;
import net.sf.openrocket.rocketcomponent.NoseCone;
import net.sf.openrocket.util.Coordinate;
import net.sf.openrocket.util.Transformation;
import java.awt.Graphics2D;
@ -56,14 +58,14 @@ public class PrintableNoseCone extends AbstractPrintable<NoseCone> {
*/
@Override
protected void draw(Graphics2D g2) {
Shape[] shapes = TransitionShapes.getShapesSide(target, Transformation.rotate_x(0d), PrintUnit.METERS.toPoints(1));
RocketComponentShape[] compShapes = TransitionShapes.getShapesSide(target, Transformation.rotate_x(0d), new Coordinate(0,0,0), PrintUnit.METERS.toPoints(1));
if (shapes != null && shapes.length > 0) {
Rectangle r = shapes[0].getBounds();
if (compShapes != null && compShapes.length > 0) {
Rectangle r = compShapes[0].shape.getBounds();
g2.translate(r.getHeight() / 2, 0);
g2.rotate(Math.PI / 2);
for (Shape shape : shapes) {
g2.draw(shape);
for (RocketComponentShape shape : compShapes) {
g2.draw(shape.shape);
}
g2.rotate(-Math.PI / 2);
}

View File

@ -8,38 +8,43 @@ import java.awt.geom.Ellipse2D;
import java.awt.geom.Rectangle2D;
public class BodyTubeShapes extends RocketComponentShapes {
public class BodyTubeShapes extends RocketComponentShape {
public static Shape[] getShapesSide(net.sf.openrocket.rocketcomponent.RocketComponent component,
Transformation transformation) {
public static RocketComponentShape[] getShapesSide(
net.sf.openrocket.rocketcomponent.RocketComponent component,
Transformation transformation,
Coordinate instanceOffset) {
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(new Coordinate(0,0,0)));
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);
}
return s;
return RocketComponentShape.toArray(s, component);
}
public static Shape[] getShapesBack(net.sf.openrocket.rocketcomponent.RocketComponent component,
Transformation transformation) {
public static RocketComponentShape[] getShapesBack(
net.sf.openrocket.rocketcomponent.RocketComponent component,
Transformation transformation,
Coordinate instanceOffset) {
net.sf.openrocket.rocketcomponent.BodyTube tube = (net.sf.openrocket.rocketcomponent.BodyTube)component;
double or = tube.getOuterRadius();
Coordinate[] start = transformation.transform(tube.toAbsolute(new Coordinate(0,0,0)));
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 s;
return RocketComponentShape.toArray(s, component);
}

View File

@ -8,16 +8,18 @@ import net.sf.openrocket.util.MathUtil;
import net.sf.openrocket.util.Transformation;
public class FinSetShapes extends RocketComponentShapes {
public class FinSetShapes extends RocketComponentShape {
// TODO: LOW: Clustering is ignored (FinSet cannot currently be clustered)
public static Shape[] getShapesSide(net.sf.openrocket.rocketcomponent.RocketComponent component,
Transformation transformation) {
public static RocketComponentShape[] getShapesSide(
net.sf.openrocket.rocketcomponent.RocketComponent component,
Transformation transformation,
Coordinate instanceOffset) {
net.sf.openrocket.rocketcomponent.FinSet finset = (net.sf.openrocket.rocketcomponent.FinSet)component;
int fins = finset.getFinCount();
int finCount = finset.getFinCount();
Transformation cantRotation = finset.getCantRotation();
Transformation baseRotation = finset.getBaseRotationTransformation();
Transformation finRotation = finset.getFinRotationTransformation();
@ -36,8 +38,8 @@ public class FinSetShapes extends RocketComponentShapes {
// Generate shapes
Shape[] s = new Shape[fins];
for (int fin=0; fin<fins; fin++) {
RocketComponentShape[] rcs = new RocketComponentShape[ finCount];
for (int fin=0; fin<finCount; fin++) {
Coordinate a;
Path2D.Float p;
@ -52,26 +54,32 @@ public class FinSetShapes extends RocketComponentShapes {
}
p.closePath();
s[fin] = p;
rcs[fin] = new RocketComponentShape( p, finset);
// Rotate fin coordinates
for (int i=0; i<finPoints.length; i++)
finPoints[i] = finRotation.transform(finPoints[i]);
}
return s;
return rcs;
}
public static Shape[] getShapesBack(net.sf.openrocket.rocketcomponent.RocketComponent component,
Transformation transformation) {
public static RocketComponentShape[] getShapesBack(
net.sf.openrocket.rocketcomponent.RocketComponent component,
Transformation transformation,
Coordinate instanceOffset) {
net.sf.openrocket.rocketcomponent.FinSet finset = (net.sf.openrocket.rocketcomponent.FinSet)component;
Shape[] toReturn;
if (MathUtil.equals(finset.getCantAngle(),0))
return uncantedShapesBack(finset, transformation);
else
return cantedShapesBack(finset, transformation);
if (MathUtil.equals(finset.getCantAngle(),0)){
toReturn = uncantedShapesBack(finset, transformation);
}else{
toReturn = cantedShapesBack(finset, transformation);
}
return RocketComponentShape.toArray( toReturn, finset);
}

View File

@ -8,37 +8,45 @@ import java.awt.geom.Ellipse2D;
import java.awt.geom.Rectangle2D;
public class LaunchLugShapes extends RocketComponentShapes {
public class LaunchLugShapes extends RocketComponentShape {
public static RocketComponentShape[] getShapesSide(
net.sf.openrocket.rocketcomponent.RocketComponent component,
Transformation transformation,
Coordinate instanceOffset) {
public static Shape[] getShapesSide(net.sf.openrocket.rocketcomponent.RocketComponent component,
Transformation transformation) {
net.sf.openrocket.rocketcomponent.LaunchLug lug = (net.sf.openrocket.rocketcomponent.LaunchLug)component;
double length = lug.getLength();
double radius = lug.getOuterRadius();
Coordinate[] start = transformation.transform(lug.toAbsolute(new Coordinate(0,0,0)));
Coordinate[] start = transformation.transform(lug.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);
}
return s;
return RocketComponentShape.toArray(s, component);
}
public static Shape[] getShapesBack(net.sf.openrocket.rocketcomponent.RocketComponent component,
Transformation transformation) {
public static RocketComponentShape[] getShapesBack(
net.sf.openrocket.rocketcomponent.RocketComponent component,
Transformation transformation,
Coordinate instanceOffset) {
net.sf.openrocket.rocketcomponent.LaunchLug lug = (net.sf.openrocket.rocketcomponent.LaunchLug)component;
double or = lug.getOuterRadius();
Coordinate[] start = transformation.transform(lug.toAbsolute(new Coordinate(0,0,0)));
Coordinate[] start = transformation.transform(lug.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 s;
return RocketComponentShape.toArray(s, component);
}
}

View File

@ -13,10 +13,13 @@ import net.sf.openrocket.util.MathUtil;
import net.sf.openrocket.util.Transformation;
public class MassComponentShapes extends RocketComponentShapes {
public class MassComponentShapes extends RocketComponentShape {
public static Shape[] getShapesSide(net.sf.openrocket.rocketcomponent.RocketComponent component,
Transformation transformation) {
public static RocketComponentShape[] getShapesSide(
net.sf.openrocket.rocketcomponent.RocketComponent component,
Transformation transformation,
Coordinate instanceOffset) {
net.sf.openrocket.rocketcomponent.MassObject tube = (net.sf.openrocket.rocketcomponent.MassObject)component;
net.sf.openrocket.rocketcomponent.MassComponent.MassComponentType type = ((net.sf.openrocket.rocketcomponent.MassComponent)component).getMassComponentType();
@ -24,7 +27,7 @@ public class MassComponentShapes extends RocketComponentShapes {
double length = tube.getLength();
double radius = tube.getRadius();
double arc = Math.min(length, 2*radius) * 0.7;
Coordinate[] start = transformation.transform(tube.toAbsolute(new Coordinate(0,0,0)));
Coordinate[] start = transformation.transform(tube.toAbsolute(instanceOffset));
Shape[] s = new Shape[start.length];
for (int i=0; i < start.length; i++) {
@ -57,23 +60,26 @@ public class MassComponentShapes extends RocketComponentShapes {
case MASSCOMPONENT:
}
return s;
return RocketComponentShape.toArray(s, component);
}
public static Shape[] getShapesBack(net.sf.openrocket.rocketcomponent.RocketComponent component,
Transformation transformation) {
public static RocketComponentShape[] getShapesBack(
net.sf.openrocket.rocketcomponent.RocketComponent component,
Transformation transformation,
Coordinate instanceOffset) {
net.sf.openrocket.rocketcomponent.MassObject tube = (net.sf.openrocket.rocketcomponent.MassObject)component;
double or = tube.getRadius();
Coordinate[] start = transformation.transform(tube.toAbsolute(new Coordinate(0,0,0)));
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 s;
return RocketComponentShape.toArray(s, component);
}
private static Shape[] addAltimeterSymbol(Shape[] baseShape){

View File

@ -8,16 +8,18 @@ import net.sf.openrocket.util.Coordinate;
import net.sf.openrocket.util.Transformation;
public class MassObjectShapes extends RocketComponentShapes {
public class MassObjectShapes extends RocketComponentShape {
public static Shape[] getShapesSide(net.sf.openrocket.rocketcomponent.RocketComponent component,
Transformation transformation) {
net.sf.openrocket.rocketcomponent.MassObject tube = (net.sf.openrocket.rocketcomponent.MassObject)component;
public static RocketComponentShape[] getShapesSide(
net.sf.openrocket.rocketcomponent.RocketComponent component,
Transformation transformation,
Coordinate instanceOffset) {
net.sf.openrocket.rocketcomponent.MassObject tube = (net.sf.openrocket.rocketcomponent.MassObject)component;
double length = tube.getLength();
double radius = tube.getRadius();
double arc = Math.min(length, 2*radius) * 0.7;
Coordinate[] start = transformation.transform(tube.toAbsolute(new Coordinate(0,0,0)));
Coordinate[] start = transformation.transform(tube.toAbsolute(instanceOffset));
Shape[] s = new Shape[start.length];
for (int i=0; i < start.length; i++) {
@ -25,23 +27,26 @@ public class MassObjectShapes extends RocketComponentShapes {
length*S,2*radius*S,arc*S,arc*S);
}
return s;
return RocketComponentShape.toArray(s, component);
}
public static Shape[] getShapesBack(net.sf.openrocket.rocketcomponent.RocketComponent component,
Transformation transformation) {
public static RocketComponentShape[] getShapesBack(
net.sf.openrocket.rocketcomponent.RocketComponent component,
Transformation transformation,
Coordinate instanceOffset) {
net.sf.openrocket.rocketcomponent.MassObject tube = (net.sf.openrocket.rocketcomponent.MassObject)component;
double or = tube.getRadius();
Coordinate[] start = transformation.transform(tube.toAbsolute(new Coordinate(0,0,0)));
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 s;
return RocketComponentShape.toArray(s, component);
}
}

View File

@ -10,39 +10,45 @@ import java.awt.geom.Path2D;
import java.awt.geom.Rectangle2D;
import java.awt.geom.RoundRectangle2D;
public class ParachuteShapes extends RocketComponentShapes {
public class ParachuteShapes extends RocketComponentShape {
public static Shape[] getShapesSide(net.sf.openrocket.rocketcomponent.RocketComponent component,
Transformation transformation) {
public static RocketComponentShape[] getShapesSide(
net.sf.openrocket.rocketcomponent.RocketComponent component,
Transformation transformation,
Coordinate instanceOffset) {
net.sf.openrocket.rocketcomponent.MassObject tube = (net.sf.openrocket.rocketcomponent.MassObject)component;
double length = tube.getLength();
double radius = tube.getRadius();
double arc = Math.min(length, 2*radius) * 0.7;
Coordinate[] start = transformation.transform(tube.toAbsolute(new Coordinate(0,0,0)));
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 addSymbol(s);
return RocketComponentShape.toArray( addSymbol(s), component);
}
public static Shape[] getShapesBack(net.sf.openrocket.rocketcomponent.RocketComponent component,
Transformation transformation) {
public static RocketComponentShape[] getShapesBack(
net.sf.openrocket.rocketcomponent.RocketComponent component,
Transformation transformation,
Coordinate instanceOffset) {
net.sf.openrocket.rocketcomponent.MassObject tube = (net.sf.openrocket.rocketcomponent.MassObject)component;
double or = tube.getRadius();
Coordinate[] start = transformation.transform(tube.toAbsolute(new Coordinate(0,0,0)));
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 s;
return RocketComponentShape.toArray( s, component);
}
private static Shape[] addSymbol(Shape[] baseShape){

View File

@ -9,10 +9,13 @@ import net.sf.openrocket.util.Coordinate;
import net.sf.openrocket.util.Transformation;
public class RingComponentShapes extends RocketComponentShapes {
public class RingComponentShapes extends RocketComponentShape {
public static RocketComponentShape[] getShapesSide(
net.sf.openrocket.rocketcomponent.RocketComponent component,
Transformation transformation,
Coordinate instanceOffset) {
public static Shape[] getShapesSide(net.sf.openrocket.rocketcomponent.RocketComponent component,
Transformation transformation) {
net.sf.openrocket.rocketcomponent.RingComponent tube = (net.sf.openrocket.rocketcomponent.RingComponent)component;
Shape[] s;
@ -21,7 +24,7 @@ public class RingComponentShapes extends RocketComponentShapes {
double ir = tube.getInnerRadius();
Coordinate[] start = transformation.transform(tube.toAbsolute(new Coordinate(0,0,0)));
Coordinate[] start = transformation.transform(tube.toAbsolute(instanceOffset));
if ((or-ir >= 0.0012) && (ir > 0)) {
// Draw outer and inner
@ -40,11 +43,11 @@ public class RingComponentShapes extends RocketComponentShapes {
length*S,2*or*S);
}
}
return s;
return RocketComponentShape.toArray( s, component);
}
public static Shape[] getShapesBack(net.sf.openrocket.rocketcomponent.RocketComponent component,
public static RocketComponentShape[] getShapesBack(net.sf.openrocket.rocketcomponent.RocketComponent component,
Transformation transformation) {
net.sf.openrocket.rocketcomponent.RingComponent tube = (net.sf.openrocket.rocketcomponent.RingComponent)component;
Shape[] s;
@ -71,7 +74,7 @@ public class RingComponentShapes extends RocketComponentShapes {
s[i] = new Ellipse2D.Double((start[i].z-or)*S,(start[i].y-or)*S,2*or*S,2*or*S);
}
}
return s;
return RocketComponentShape.toArray( s, component);
}
}

View File

@ -0,0 +1,83 @@
package net.sf.openrocket.gui.rocketfigure;
import java.awt.Shape;
import net.sf.openrocket.gui.scalefigure.RocketFigure;
import net.sf.openrocket.rocketcomponent.RocketComponent;
import net.sf.openrocket.startup.Application;
import net.sf.openrocket.util.Coordinate;
import net.sf.openrocket.util.LineStyle;
import net.sf.openrocket.util.Transformation;
/**
* A catch-all, no-operation drawing component.
*/
public class RocketComponentShape {
protected static final double S = RocketFigure.EXTRA_SCALE;
final public boolean hasShape;
final public Shape shape;
final public net.sf.openrocket.util.Color color;
final public LineStyle lineStyle;
final public RocketComponent component;
protected RocketComponentShape(){
this.hasShape = false;
this.shape = null;
this.color = null;
this.lineStyle = null;
this.component=null;
}
public RocketComponentShape( final Shape _shape, final RocketComponent _comp){
this.shape = _shape;
this.color = _comp.getColor();
this.lineStyle = _comp.getLineStyle();
this.component = _comp;
if( null == _shape ){
this.hasShape = false;
}else{
this.hasShape = true;
}
}
public RocketComponent getComponent(){
return this.component;
}
public static RocketComponentShape[] getShapesSide(
net.sf.openrocket.rocketcomponent.RocketComponent component,
Transformation transformation,
Coordinate instanceOffset) {
// no-op
Application.getExceptionHandler().handleErrorCondition("ERROR: RocketComponent.getShapesSide called with "
+ component);
return new RocketComponentShape[0];
}
public static RocketComponentShape[] getShapesBack(
net.sf.openrocket.rocketcomponent.RocketComponent component,
Transformation transformation,
Coordinate instanceOffset) { // no-op
Application.getExceptionHandler().handleErrorCondition("ERROR: RocketComponent.getShapesBack called with "
+component);
return new RocketComponentShape[0];
}
public static RocketComponentShape[] toArray( final Shape[] shapeArray, final RocketComponent rc){
RocketComponentShape[] toReturn = new RocketComponentShape[ shapeArray.length];
for ( int curShapeIndex=0;curShapeIndex<shapeArray.length; curShapeIndex++){
Shape curShape = shapeArray[curShapeIndex ];
toReturn[curShapeIndex] = new RocketComponentShape( curShape, rc);
}
return toReturn;
}
}

View File

@ -1,35 +0,0 @@
package net.sf.openrocket.gui.rocketfigure;
import java.awt.Shape;
import net.sf.openrocket.gui.scalefigure.RocketFigure;
import net.sf.openrocket.startup.Application;
import net.sf.openrocket.util.Transformation;
/**
* A catch-all, no-operation drawing component.
*/
public class RocketComponentShapes {
protected static final double S = RocketFigure.EXTRA_SCALE;
public static Shape[] getShapesSide(net.sf.openrocket.rocketcomponent.RocketComponent component,
Transformation t) {
// no-op
Application.getExceptionHandler().handleErrorCondition("ERROR: RocketComponent.getShapesSide called with "
+ component);
return new Shape[0];
}
public static Shape[] getShapesBack(net.sf.openrocket.rocketcomponent.RocketComponent component,
Transformation t) {
// no-op
Application.getExceptionHandler().handleErrorCondition("ERROR: RocketComponent.getShapesBack called with "
+component);
return new Shape[0];
}
}

View File

@ -9,39 +9,45 @@ import java.awt.geom.Path2D;
import java.awt.geom.Rectangle2D;
import java.awt.geom.RoundRectangle2D;
public class ShockCordShapes extends RocketComponentShapes {
public class ShockCordShapes extends RocketComponentShape {
public static RocketComponentShape[] getShapesSide(
net.sf.openrocket.rocketcomponent.RocketComponent component,
Transformation transformation,
Coordinate instanceOffset) {
public static Shape[] getShapesSide(net.sf.openrocket.rocketcomponent.RocketComponent component,
Transformation transformation) {
net.sf.openrocket.rocketcomponent.MassObject tube = (net.sf.openrocket.rocketcomponent.MassObject)component;
double length = tube.getLength();
double radius = tube.getRadius();
double arc = Math.min(length, 2*radius) * 0.7;
Coordinate[] start = transformation.transform(tube.toAbsolute(new Coordinate(0,0,0)));
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 addSymbol(s);
return RocketComponentShape.toArray( addSymbol(s), component);
}
public static Shape[] getShapesBack(net.sf.openrocket.rocketcomponent.RocketComponent component,
Transformation transformation) {
public static RocketComponentShape[] getShapesBack(
net.sf.openrocket.rocketcomponent.RocketComponent component,
Transformation transformation,
Coordinate instanceOffset) {
net.sf.openrocket.rocketcomponent.MassObject tube = (net.sf.openrocket.rocketcomponent.MassObject)component;
double or = tube.getRadius();
Coordinate[] start = transformation.transform(tube.toAbsolute(new Coordinate(0,0,0)));
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 s;
return RocketComponentShape.toArray( s, component);
}
private static Shape[] addSymbol(Shape[] baseShape){

View File

@ -9,39 +9,45 @@ import java.awt.geom.Path2D;
import java.awt.geom.Rectangle2D;
import java.awt.geom.RoundRectangle2D;
public class StreamerShapes extends RocketComponentShapes {
public class StreamerShapes extends RocketComponentShape {
public static RocketComponentShape[] getShapesSide(
net.sf.openrocket.rocketcomponent.RocketComponent component,
Transformation transformation,
Coordinate instanceOffset) {
public static Shape[] getShapesSide(net.sf.openrocket.rocketcomponent.RocketComponent component,
Transformation transformation) {
net.sf.openrocket.rocketcomponent.MassObject tube = (net.sf.openrocket.rocketcomponent.MassObject)component;
double length = tube.getLength();
double radius = tube.getRadius();
double arc = Math.min(length, 2*radius) * 0.7;
Coordinate[] start = transformation.transform(tube.toAbsolute(new Coordinate(0,0,0)));
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 addSymbol(s);
return RocketComponentShape.toArray(addSymbol(s), component);
}
public static Shape[] getShapesBack(net.sf.openrocket.rocketcomponent.RocketComponent component,
Transformation transformation) {
public static RocketComponentShape[] getShapesBack(
net.sf.openrocket.rocketcomponent.RocketComponent component,
Transformation transformation,
Coordinate instanceOffset) {
net.sf.openrocket.rocketcomponent.MassObject tube = (net.sf.openrocket.rocketcomponent.MassObject)component;
double or = tube.getRadius();
Coordinate[] start = transformation.transform(tube.toAbsolute(new Coordinate(0,0,0)));
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 s;
return RocketComponentShape.toArray(s, component);
}
private static Shape[] addSymbol(Shape[] baseShape){

View File

@ -9,7 +9,7 @@ import java.awt.geom.Path2D;
import java.util.ArrayList;
public class SymmetricComponentShapes extends RocketComponentShapes {
public class SymmetricComponentShapes extends RocketComponentShape {
private static final int MINPOINTS = 91;
private static final double ACCEPTABLE_ANGLE = Math.cos(7.0 * Math.PI / 180.0);
@ -17,13 +17,19 @@ public class SymmetricComponentShapes extends RocketComponentShapes {
// TODO: LOW: Uses only first component of cluster (not currently clusterable)
public static Shape[] getShapesSide(net.sf.openrocket.rocketcomponent.RocketComponent component,
Transformation transformation) {
return getShapesSide(component, transformation, S);
public static RocketComponentShape[] getShapesSide(
net.sf.openrocket.rocketcomponent.RocketComponent component,
Transformation transformation,
Coordinate instanceOffset) {
return getShapesSide(component, transformation, instanceOffset, S);
}
public static Shape[] getShapesSide(net.sf.openrocket.rocketcomponent.RocketComponent component,
Transformation transformation, final double scaleFactor) {
public static RocketComponentShape[] getShapesSide(
net.sf.openrocket.rocketcomponent.RocketComponent component,
Transformation transformation,
Coordinate instanceOffset,
final double scaleFactor) {
net.sf.openrocket.rocketcomponent.SymmetricComponent c = (net.sf.openrocket.rocketcomponent.SymmetricComponent) component;
int i;
@ -94,7 +100,7 @@ public class SymmetricComponentShapes extends RocketComponentShapes {
//s[len] = path;
//return s;
return new Shape[] { path };
return new RocketComponentShape[] { new RocketComponentShape(path, component) };
}
private static boolean angleAcceptable(Coordinate v1, Coordinate v2, Coordinate v3) {

View File

@ -10,20 +10,25 @@ import java.awt.geom.Path2D;
import java.awt.geom.Rectangle2D;
public class TransitionShapes extends RocketComponentShapes {
public class TransitionShapes extends RocketComponentShape {
// TODO: LOW: Uses only first component of cluster (not currently clusterable).
public static Shape[] getShapesSide(net.sf.openrocket.rocketcomponent.RocketComponent component,
Transformation transformation) {
return getShapesSide(component, transformation, S);
public static RocketComponentShape[] getShapesSide(
net.sf.openrocket.rocketcomponent.RocketComponent component,
Transformation transformation,
Coordinate instanceOffset) {
return getShapesSide(component, transformation, instanceOffset, S);
}
public static Shape[] getShapesSide(net.sf.openrocket.rocketcomponent.RocketComponent component,
Transformation transformation, final double scaleFactor) {
public static RocketComponentShape[] getShapesSide(
net.sf.openrocket.rocketcomponent.RocketComponent component,
Transformation transformation,
Coordinate instanceOffset,
final double scaleFactor) {
net.sf.openrocket.rocketcomponent.Transition transition = (net.sf.openrocket.rocketcomponent.Transition)component;
Shape[] mainShapes;
RocketComponentShape[] mainShapes;
// Simpler shape for conical transition, others use the method from SymmetricComponent
if (transition.getType() == Transition.Shape.CONICAL) {
@ -31,7 +36,7 @@ public class TransitionShapes extends RocketComponentShapes {
double r1 = transition.getForeRadius();
double r2 = transition.getAftRadius();
Coordinate start = transformation.transform(transition.
toAbsolute(Coordinate.NUL)[0]);
toAbsolute(instanceOffset)[0]);
Path2D.Float path = new Path2D.Float();
path.moveTo(start.x* scaleFactor, r1* scaleFactor);
@ -40,9 +45,9 @@ public class TransitionShapes extends RocketComponentShapes {
path.lineTo(start.x* scaleFactor, -r1* scaleFactor);
path.closePath();
mainShapes = new Shape[] { path };
mainShapes = new RocketComponentShape[] { new RocketComponentShape( path, component) };
} else {
mainShapes = SymmetricComponentShapes.getShapesSide(component, transformation, scaleFactor);
mainShapes = SymmetricComponentShapes.getShapesSide(component, transformation, instanceOffset, scaleFactor);
}
Rectangle2D.Double shoulder1=null, shoulder2=null;
@ -71,7 +76,7 @@ public class TransitionShapes extends RocketComponentShapes {
int i;
for (i=0; i < mainShapes.length; i++) {
shapes[i] = mainShapes[i];
shapes[i] = mainShapes[i].shape;
}
if (shoulder1 != null) {
shapes[i] = shoulder1;
@ -80,21 +85,27 @@ public class TransitionShapes extends RocketComponentShapes {
if (shoulder2 != null) {
shapes[i] = shoulder2;
}
return shapes;
return RocketComponentShape.toArray( shapes, component);
}
public static Shape[] getShapesBack(net.sf.openrocket.rocketcomponent.RocketComponent component,
Transformation transformation) {
public static RocketComponentShape[] getShapesBack(
net.sf.openrocket.rocketcomponent.RocketComponent component,
Transformation transformation,
Coordinate instanceOffset) {
net.sf.openrocket.rocketcomponent.Transition transition = (net.sf.openrocket.rocketcomponent.Transition)component;
double r1 = transition.getForeRadius();
double r2 = transition.getAftRadius();
Coordinate center = instanceOffset;
// adjust center heree... somehow
Shape[] s = new Shape[2];
s[0] = new Ellipse2D.Double(-r1*S,-r1*S,2*r1*S,2*r1*S);
s[1] = new Ellipse2D.Double(-r2*S,-r2*S,2*r2*S,2*r2*S);
return s;
return RocketComponentShape.toArray(s, component);
}

View File

@ -8,10 +8,13 @@ import java.awt.geom.Ellipse2D;
import java.awt.geom.Rectangle2D;
public class TubeFinSetShapes extends RocketComponentShapes {
public class TubeFinSetShapes extends RocketComponentShape {
public static Shape[] getShapesSide(net.sf.openrocket.rocketcomponent.RocketComponent component,
Transformation transformation) {
public static RocketComponentShape[] getShapesSide(
net.sf.openrocket.rocketcomponent.RocketComponent component,
Transformation transformation,
Coordinate instanceOffset) {
net.sf.openrocket.rocketcomponent.TubeFinSet finset = (net.sf.openrocket.rocketcomponent.TubeFinSet)component;
int fins = finset.getFinCount();
@ -19,7 +22,7 @@ public class TubeFinSetShapes extends RocketComponentShapes {
double outerradius = finset.getOuterRadius();
double bodyradius = finset.getBodyRadius();
Coordinate[] start = finset.toAbsolute(new Coordinate(0,0,0));
Coordinate[] start = finset.toAbsolute(instanceOffset);
Transformation baseRotation = finset.getBaseRotationTransformation();
Transformation finRotation = finset.getFinRotationTransformation();
@ -36,19 +39,22 @@ public class TubeFinSetShapes extends RocketComponentShapes {
s[i] = new Rectangle2D.Double(start[0].x*S,(start[0].y-outerradius)*S,length*S,2*outerradius*S);
start = finRotation.transform(start);
}
return s;
return RocketComponentShape.toArray(s, component);
}
public static Shape[] getShapesBack(net.sf.openrocket.rocketcomponent.RocketComponent component,
Transformation transformation) {
public static RocketComponentShape[] getShapesBack(
net.sf.openrocket.rocketcomponent.RocketComponent component,
Transformation transformation,
Coordinate instanceOffset) {
net.sf.openrocket.rocketcomponent.TubeFinSet finset = (net.sf.openrocket.rocketcomponent.TubeFinSet)component;
int fins = finset.getFinCount();
double outerradius = finset.getOuterRadius();
double bodyradius = finset.getBodyRadius();
Coordinate[] start = finset.toAbsolute(new Coordinate(0,0,0));
Coordinate[] start = finset.toAbsolute( instanceOffset);
Transformation baseRotation = finset.getBaseRotationTransformation();
Transformation finRotation = finset.getFinRotationTransformation();
@ -63,7 +69,7 @@ public class TubeFinSetShapes extends RocketComponentShapes {
s[i] = new Ellipse2D.Double((start[0].z-outerradius)*S,(start[0].y-outerradius)*S,2*outerradius*S,2*outerradius*S);
start = finRotation.transform(start);
}
return s;
return RocketComponentShape.toArray(s, component);
}

View File

@ -25,7 +25,10 @@ import net.sf.openrocket.gui.util.SwingPreferences;
import net.sf.openrocket.motor.Motor;
import net.sf.openrocket.rocketcomponent.Configuration;
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.gui.rocketfigure.RocketComponentShape;
import net.sf.openrocket.gui.scalefigure.RocketPanel;
import net.sf.openrocket.startup.Application;
import net.sf.openrocket.util.BugException;
@ -71,9 +74,8 @@ public class RocketFigure extends AbstractScaleFigure {
/*
* figureComponents contains the corresponding RocketComponents of the figureShapes
*/
private final ArrayList<Shape> figureShapes = new ArrayList<Shape>();
private final ArrayList<RocketComponent> figureComponents =
new ArrayList<RocketComponent>();
private final ArrayList<RocketComponentShape> figureShapes = new ArrayList<RocketComponentShape>();
private double minX = 0, maxX = 0, maxR = 0;
// Figure width and height in SI-units and pixels
@ -172,7 +174,7 @@ public class RocketFigure extends AbstractScaleFigure {
this.currentViewType = type;
updateFigure();
}
/**
* Updates the figure shapes and figure size.
@ -180,20 +182,11 @@ public class RocketFigure extends AbstractScaleFigure {
@Override
public void updateFigure() {
figureShapes.clear();
figureComponents.clear();
calculateSize();
// Get shapes for all active components
for (RocketComponent c : configuration) {
Shape[] s = getShapes( this.currentViewType, c, this.transformation);
for (int i = 0; i < s.length; i++) {
figureShapes.add(s[i]);
figureComponents.add(c);
}
}
Rocket theRocket = configuration.getRocket();
Coordinate zero = new Coordinate(0,0,0);
getShapeTree( figureShapes, theRocket, zero);
System.err.println(" updating the RocketFigure.");
repaint();
@ -298,8 +291,8 @@ public class RocketFigure extends AbstractScaleFigure {
// Draw all shapes
for (int i = 0; i < figureShapes.size(); i++) {
RocketComponent c = figureComponents.get(i);
Shape s = figureShapes.get(i);
RocketComponentShape rcs = figureShapes.get(i);
RocketComponent c = rcs.getComponent();
boolean selected = false;
// Check if component is in the selection
@ -311,13 +304,13 @@ public class RocketFigure extends AbstractScaleFigure {
}
// Set component color and line style
net.sf.openrocket.util.Color color = c.getColor();
net.sf.openrocket.util.Color color = rcs.color;
if (color == null) {
color = Application.getPreferences().getDefaultColor(c.getClass());
}
g2.setColor(ColorConversion.toAwtColor(color));
LineStyle style = c.getLineStyle();
LineStyle style = rcs.lineStyle;
if (style == null)
style = Application.getPreferences().getDefaultLineStyle(c.getClass());
@ -337,7 +330,7 @@ public class RocketFigure extends AbstractScaleFigure {
g2.setRenderingHint(RenderingHints.KEY_STROKE_CONTROL,
RenderingHints.VALUE_STROKE_NORMALIZE);
}
g2.draw(s);
g2.draw(rcs.shape);
}
@ -424,13 +417,78 @@ public class RocketFigure extends AbstractScaleFigure {
LinkedHashSet<RocketComponent> l = new LinkedHashSet<RocketComponent>();
for (int i = 0; i < figureShapes.size(); i++) {
if (figureShapes.get(i).contains(p))
l.add(figureComponents.get(i));
RocketComponentShape rcs = this.figureShapes.get(i);
if (rcs.shape.contains(p))
l.add(rcs.component);
}
return l.toArray(new RocketComponent[0]);
}
// NOTE: Recursive function
private void getShapeTree(
ArrayList<RocketComponentShape> allShapes, // this is the output parameter
final RocketComponent comp,
final Coordinate parentOffset){
RocketPanel.VIEW_TYPE viewType = this.currentViewType;
Transformation viewTransform = this.transformation;
// TODO: Implement actual locations in the components
Coordinate componentLocation = new Coordinate(comp.getPositionValue(),0,0);
if( comp instanceof MultipleComponent ){
MultipleComponent multi = (MultipleComponent)comp;
int instanceCount;
instanceCount = multi.getInstanceCount();
// get m instance locations
Coordinate[] instanceOffsets = multi.getInstanceOffsets();
assert(false);
assert( instanceOffsets.length == instanceCount );
// 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);
}
}
}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 );
}
}
// recurse to each child
for( RocketComponent child: comp.getChildren() ){
getShapeTree( allShapes, child, parentOffset);
}
}
return;
}
/**
* Gets the shapes required to draw the component.
@ -439,32 +497,32 @@ public class RocketFigure extends AbstractScaleFigure {
* @param params
* @return
*/
private static Shape[] getShapes(final RocketPanel.VIEW_TYPE type, final RocketComponent component, final Transformation transformation) {
private static RocketComponentShape[] getThisShape(final RocketPanel.VIEW_TYPE viewType, final RocketComponent component, final Coordinate instanceOffset, final Transformation transformation) {
Reflection.Method m;
// Find the appropriate method
switch (type) {
switch (viewType) {
case SideView:
m = Reflection.findMethod(ROCKET_FIGURE_PACKAGE, component, ROCKET_FIGURE_SUFFIX, "getShapesSide",
RocketComponent.class, Transformation.class);
RocketComponent.class, Transformation.class, Coordinate.class);
break;
case BackView:
m = Reflection.findMethod(ROCKET_FIGURE_PACKAGE, component, ROCKET_FIGURE_SUFFIX, "getShapesBack",
RocketComponent.class, Transformation.class);
RocketComponent.class, Transformation.class, Coordinate.class);
break;
default:
throw new BugException("Unknown figure type = " + type);
throw new BugException("Unknown figure type = " + viewType);
}
if (m == null) {
Application.getExceptionHandler().handleErrorCondition("ERROR: Rocket figure paint method not found for "
+ component);
return new Shape[0];
return new RocketComponentShape[0];
}
return (Shape[]) m.invokeStatic(component, transformation);
return (RocketComponentShape[]) m.invokeStatic(component, transformation, instanceOffset);
}