Merge pull request #513 from teyrana/refactor_instance_map

Refactor instance map
This commit is contained in:
Wes Cravens 2019-01-26 07:14:39 -06:00 committed by GitHub
commit 1abf0d3834
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
25 changed files with 560 additions and 329 deletions

View File

@ -4,6 +4,7 @@ import java.util.ArrayDeque;
import java.util.Collection;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Queue;
import org.slf4j.Logger;
@ -18,6 +19,7 @@ import net.sf.openrocket.util.BoundingBox;
import net.sf.openrocket.util.Coordinate;
import net.sf.openrocket.util.MathUtil;
import net.sf.openrocket.util.Monitorable;
import net.sf.openrocket.util.Transformation;
/**
@ -36,9 +38,9 @@ public class FlightConfiguration implements FlightConfigurableParameter<FlightCo
protected final Rocket rocket;
protected final FlightConfigurationId fcid;
private static int instanceCount=0;
private static int configurationInstanceCount=0;
// made public for testing.... there is probably a better way
public final int instanceNumber;
public final int configurationInstanceId;
private class StageFlags implements Cloneable {
public boolean active = true;
@ -83,7 +85,7 @@ public class FlightConfiguration implements FlightConfigurableParameter<FlightCo
}
this.rocket = rocket;
this.configurationName = null;
this.instanceNumber = instanceCount++;
this.configurationInstanceId = configurationInstanceCount++;
updateStages();
updateMotors();
@ -172,9 +174,29 @@ public class FlightConfiguration implements FlightConfigurableParameter<FlightCo
return stages.get(stageNumber).active;
}
public Collection<RocketComponent> getAllComponents() {
Queue<RocketComponent> toProcess = new ArrayDeque<RocketComponent>();
toProcess.offer(this.rocket);
ArrayList<RocketComponent> toReturn = new ArrayList<>();
while (!toProcess.isEmpty()) {
RocketComponent comp = toProcess.poll();
toReturn.add(comp);
for (RocketComponent child : comp.getChildren()) {
if (!(child instanceof AxialStage)) {
toProcess.offer(child);
}
}
}
return toReturn;
}
// this method is deprecated because it ignores instancing of parent components (e.g. Strapons or pods )
// if you're calling this method, you're probably not getting the numbers you expect.
// depending on your context, this may or may not be what you want.
// recomend migrating to either: `getAllComponents` or `getActiveInstances`
@Deprecated
public Collection<RocketComponent> getActiveComponents() {
Queue<RocketComponent> toProcess = new ArrayDeque<RocketComponent>(this.getActiveStages());
@ -193,6 +215,49 @@ public class FlightConfiguration implements FlightConfigurableParameter<FlightCo
return toReturn;
}
/*
* Generates a read-only, instance-aware collection of the components for this rocket & configuration
*
* TODO: swap in this function for the 'getActiveComponents() function, above; ONLY WHEN READY / MATURE!
*/
public InstanceMap getActiveInstances() {
InstanceMap contexts = new InstanceMap();
getContextListAt( this.rocket, contexts, Transformation.IDENTITY);
return contexts;
}
private InstanceMap getContextListAt(final RocketComponent component, final InstanceMap results, final Transformation parentTransform ){
final int instanceCount = component.getInstanceCount();
final Coordinate[] allOffsets = component.getInstanceOffsets();
final double[] allAngles = component.getInstanceAngles();
final boolean active = this.isComponentActive(component);
final Transformation compLocTransform = Transformation.getTranslationTransform( component.getPosition() );
final Transformation componentTransform = parentTransform.applyTransformation(compLocTransform);
// generate the Instance's Context:
for(int currentInstanceNumber=0; currentInstanceNumber < instanceCount; currentInstanceNumber++) {
final Coordinate instanceOffset = allOffsets[currentInstanceNumber];
final Transformation offsetTransform = Transformation.getTranslationTransform( instanceOffset );
final double instanceAngle = allAngles[currentInstanceNumber];
final Transformation angleTransform = Transformation.getAxialRotation(instanceAngle);
final Transformation currentTransform = componentTransform.applyTransformation(offsetTransform)
.applyTransformation(angleTransform);
// constructs entry in-place
results.emplace(component, active, currentInstanceNumber, currentTransform);
for(RocketComponent child : component.getChildren()) {
getContextListAt(child, results, currentTransform);
}
}
return results;
}
public List<AxialStage> getActiveStages() {
List<AxialStage> activeStages = new ArrayList<>();
@ -534,14 +599,14 @@ public class FlightConfiguration implements FlightConfigurableParameter<FlightCo
}
public String toDebug() {
return this.fcid.toDebug()+" (#"+instanceNumber+") "+ getOneLineMotorDescription();
return this.fcid.toDebug()+" (#"+configurationInstanceId+") "+ getOneLineMotorDescription();
}
// DEBUG / DEVEL
public String toStageListDetail() {
StringBuilder buf = new StringBuilder();
buf.append(String.format("\nDumping %d stages for config: %s: (%s)(#: %d)\n",
stages.size(), getName(), getId().toShortKey(), instanceNumber));
stages.size(), getName(), getId().toShortKey(), configurationInstanceId));
final String fmt = " [%-2s][%4s]: %6s \n";
buf.append(String.format(fmt, "#", "?actv", "Name"));
for (StageFlags flags : stages.values()) {
@ -556,7 +621,7 @@ public class FlightConfiguration implements FlightConfigurableParameter<FlightCo
public String toMotorDetail(){
StringBuilder buf = new StringBuilder();
buf.append(String.format("\nDumping %2d Motors for configuration %s (%s)(#: %s)\n",
motors.size(), getName(), getId().toShortKey(), this.instanceNumber));
motors.size(), getName(), getId().toShortKey(), this.configurationInstanceId));
for( MotorConfiguration curConfig : this.motors.values() ){
boolean active=this.isStageActive( curConfig.getMount().getStage().getStageNumber());

View File

@ -0,0 +1,59 @@
package net.sf.openrocket.rocketcomponent;
import net.sf.openrocket.util.Coordinate;
import net.sf.openrocket.util.Transformation;
/**
*
* @author teyrana (aka Daniel Williams) <equipoise@gmail.com>
*
*/
public class InstanceContext {
// =========== Public Functions ========================
@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
InstanceContext other = (InstanceContext) obj;
return (component.equals(other.component) && transform.equals(other.transform));
}
@Override
public int hashCode() {
return (int) (component.hashCode());
}
public InstanceContext(final RocketComponent _component, final boolean _active, final int _instanceNumber, final Transformation _transform) {
component = _component;
active = _active;
instanceNumber = _instanceNumber;
transform = _transform;
}
@Override
public String toString() {
return String.format("Context for %s #%d", component);
}
public Coordinate getLocation() {
return transform.transform(Coordinate.ZERO);
}
// =========== Instance Member Variables ========================
// ==== public ====
final public RocketComponent component;
final public boolean active;
final public int instanceNumber;
final public Transformation transform;
// =========== Private Instance Functions ========================
}

View File

@ -0,0 +1,73 @@
package net.sf.openrocket.rocketcomponent;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import net.sf.openrocket.util.Transformation;
/**
*
* @author teyrana (aka Daniel Williams) <equipoise@gmail.com>
*
*/
public class InstanceMap extends HashMap<RocketComponent, ArrayList<InstanceContext>> {
// =========== Public Functions ========================
// public InstanceMap() {}
public int count(final RocketComponent key) {
if(containsKey(key)){
return get(key).size();
}else {
return 0;
}
}
public void emplace(final RocketComponent component, boolean active, int number, final Transformation xform) {
final RocketComponent key = component;
if(!containsKey(component)) {
put(key, new ArrayList<>());
}
final InstanceContext context = new InstanceContext(component, active, number, xform);
get(key).add(context);
}
public List<InstanceContext> getInstanceContexts(final RocketComponent key) {
return get(key);
}
// this is primarily for debugging.
@Override
public String toString() {
StringBuffer buffer = new StringBuffer();
int outerIndex = 0;
buffer.append(">> Printing InstanceMap:\n");
for(Map.Entry<RocketComponent, ArrayList<InstanceContext>> entry: entrySet() ) {
final RocketComponent key = entry.getKey();
final ArrayList<InstanceContext> contexts = entry.getValue();
buffer.append(String.format("....[% 2d]:[%s]\n", outerIndex, key.getName()));
outerIndex++;
int innerIndex = 0;
for(InstanceContext ctxt: contexts ) {
buffer.append(String.format("........[@% 2d][% 2d] %s\n", innerIndex, ctxt.instanceNumber, ctxt.getLocation().toPreciseString()));
innerIndex++;
}
}
return buffer.toString();
}
// =========== Instance Member Variables ========================
// =========== Private Instance Functions ========================
}

View File

@ -32,7 +32,6 @@ import net.sf.openrocket.rocketcomponent.FinSet.CrossSection;
import net.sf.openrocket.rocketcomponent.FlightConfiguration;
import net.sf.openrocket.rocketcomponent.FlightConfigurationId;
import net.sf.openrocket.rocketcomponent.FreeformFinSet;
import net.sf.openrocket.rocketcomponent.IllegalFinPointException;
import net.sf.openrocket.rocketcomponent.InnerTube;
import net.sf.openrocket.rocketcomponent.InternalComponent;
import net.sf.openrocket.rocketcomponent.LaunchLug;
@ -862,7 +861,7 @@ public class TestRockets {
// ====== Payload Stage ======
// ====== ====== ====== ======
AxialStage payloadStage = new AxialStage();
payloadStage.setName("Payload Fairing");
payloadStage.setName("Payload Fairing Stage");
rocket.addChild(payloadStage);
{

View File

@ -5,14 +5,16 @@ import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertThat;
import static org.junit.Assert.assertTrue;
import java.util.List;
import org.junit.Test;
import net.sf.openrocket.util.Coordinate;
import net.sf.openrocket.util.MathUtil;
import net.sf.openrocket.util.TestRockets;
import net.sf.openrocket.util.BaseTestCase.BaseTestCase;
public class FlightConfigurationTest extends BaseTestCase {
private final static double EPSILON = MathUtil.EPSILON*1E3;
/**
@ -155,7 +157,6 @@ public class FlightConfigurationTest extends BaseTestCase {
// test explicitly setting all stages active
config.setAllStages();
}
/**
@ -326,5 +327,151 @@ public class FlightConfigurationTest extends BaseTestCase {
assertThat("active motor count doesn't match: ", actualMotorCount, equalTo(expectedMotorCount));
}
@Test
public void testIterateComponents() {
Rocket rocket = TestRockets.makeFalcon9Heavy();
FlightConfiguration selected = rocket.getSelectedConfiguration();
selected.clearAllStages();
selected.toggleStage(2);
// vvvv Test Target vvvv
InstanceMap instances = selected.getActiveInstances();
// ^^^^ Test Target ^^^^
// Payload Stage
final AxialStage coreStage = (AxialStage)rocket.getChild(1);
{ // Core Stage
final List<InstanceContext> coreStageContextList = instances.getInstanceContexts(coreStage);
final InstanceContext coreStageContext = coreStageContextList.get(0);
assertThat(coreStageContext.component.getClass(), equalTo(AxialStage.class));
assertThat(coreStageContext.component.getID(), equalTo(rocket.getChild(1).getID()));
assertThat(coreStageContext.component.getInstanceCount(), equalTo(1));
final Coordinate coreLocation = coreStageContext.getLocation();
assertEquals(coreLocation.x, 0.564, EPSILON);
assertEquals(coreLocation.y, 0.0, EPSILON);
assertEquals(coreLocation.z, 0.0, EPSILON);
//... skip uninteresting component
}
// Booster Stage
{ // instance #1
final ParallelStage boosterStage = (ParallelStage)coreStage.getChild(0).getChild(0);
final List<InstanceContext> boosterStageContextList = instances.getInstanceContexts(boosterStage);
final InstanceContext boosterStage0Context = boosterStageContextList.get(0);
assertThat(boosterStage0Context.component.getClass(), equalTo(ParallelStage.class));
assertThat(boosterStage0Context.component.getID(), equalTo(boosterStage.getID()));
assertThat(boosterStage0Context.instanceNumber, equalTo(0));
{
final Coordinate loc = boosterStage0Context.getLocation();
assertEquals(loc.x, 0.484, EPSILON);
assertEquals(loc.y, 0.077, EPSILON);
assertEquals(loc.z, 0.0, EPSILON);
}
final InstanceContext boosterStage1Context = boosterStageContextList.get(1);
assertThat(boosterStage1Context.component.getClass(), equalTo(ParallelStage.class));
assertThat(boosterStage1Context.component.getID(), equalTo(boosterStage.getID()));
assertThat(boosterStage1Context.instanceNumber, equalTo(1));
{
final Coordinate loc = boosterStage1Context.getLocation();
assertEquals(loc.x, 0.484, EPSILON);
assertEquals(loc.y, -0.077, EPSILON);
assertEquals(loc.z, 0.0, EPSILON);
}
{ // Booster Body:
final BodyTube boosterBody = (BodyTube)boosterStage.getChild(1);
final List<InstanceContext> boosterBodyContextList = instances.getInstanceContexts(boosterBody);
// this is the instance number rocket-wide
final InstanceContext boosterBodyContext = boosterBodyContextList.get(1);
// this is the instance number per-parent
assertThat(boosterBodyContext.instanceNumber, equalTo(0));
assertThat(boosterBodyContext.component.getClass(), equalTo(BodyTube.class));
final Coordinate bodyTubeLocation = boosterBodyContext.getLocation();
assertEquals(bodyTubeLocation.x, 0.564, EPSILON);
assertEquals(bodyTubeLocation.y, -0.077, EPSILON);
assertEquals(bodyTubeLocation.z, 0.0, EPSILON);
{ // Booster::Motor Tubes ( x2 x4)
final InnerTube boosterMMT = (InnerTube)boosterBody.getChild(0);
final List<InstanceContext> mmtContextList = instances.getInstanceContexts(boosterMMT);
assertEquals(8, mmtContextList.size());
final InstanceContext motorTubeContext0 = mmtContextList.get(4);
assertThat(motorTubeContext0.component.getClass(), equalTo(InnerTube.class));
assertThat(motorTubeContext0.instanceNumber, equalTo(0));
final Coordinate motorTube0Location = motorTubeContext0.getLocation();
assertEquals(motorTube0Location.x, 1.214, EPSILON);
assertEquals(motorTube0Location.y, -0.062, EPSILON);
assertEquals(motorTube0Location.z, -0.015, EPSILON);
final InstanceContext motorTubeContext1 = mmtContextList.get(5);
assertThat(motorTubeContext1.component.getClass(), equalTo(InnerTube.class));
assertThat(motorTubeContext1.instanceNumber, equalTo(1));
final Coordinate motorTube1Location = motorTubeContext1.getLocation();
assertEquals(motorTube1Location.x, 1.214, EPSILON);
assertEquals(motorTube1Location.y, -0.092, EPSILON);
assertEquals(motorTube1Location.z, -0.015, EPSILON);
final InstanceContext motorTubeContext2 = mmtContextList.get(6);
assertThat(motorTubeContext2.component.getClass(), equalTo(InnerTube.class));
assertThat(motorTubeContext2.instanceNumber, equalTo(2));
final Coordinate motorTube2Location = motorTubeContext2.getLocation();
assertEquals(motorTube2Location.x, 1.214, EPSILON);
assertEquals(motorTube2Location.y, -0.092, EPSILON);
assertEquals(motorTube2Location.z, 0.015, EPSILON);
final InstanceContext motorTubeContext3 = mmtContextList.get(7);
assertThat(motorTubeContext3.component.getClass(), equalTo(InnerTube.class));
assertThat(motorTubeContext3.instanceNumber, equalTo(3));
final Coordinate motorTube3Location = motorTubeContext3.getLocation();
assertEquals(motorTube3Location.x, 1.214, EPSILON);
assertEquals(motorTube3Location.y, -0.062, EPSILON);
assertEquals(motorTube3Location.z, 0.015, EPSILON);
}{ // Booster::Fins::Instances ( x2 x3)
final FinSet fins = (FinSet)boosterBody.getChild(1);
final List<InstanceContext> finContextList = instances.getInstanceContexts(fins);
assertEquals(6, finContextList.size());
final InstanceContext boosterFinContext0 = finContextList.get(3);
assertThat(boosterFinContext0.component.getClass(), equalTo(TrapezoidFinSet.class));
assertThat(boosterFinContext0.instanceNumber, equalTo(0));
final Coordinate boosterFin0Location = boosterFinContext0.getLocation();
assertEquals(boosterFin0Location.x, 1.044, EPSILON);
assertEquals(boosterFin0Location.y, -0.104223611, EPSILON);
assertEquals(boosterFin0Location.z, -0.027223611, EPSILON);
final InstanceContext boosterFinContext1 = finContextList.get(4);
assertThat(boosterFinContext1.component.getClass(), equalTo(TrapezoidFinSet.class));
assertThat(boosterFinContext1.instanceNumber, equalTo(1));
final Coordinate boosterFin1Location = boosterFinContext1.getLocation();
assertEquals(boosterFin1Location.x, 1.044, EPSILON);
assertEquals(boosterFin1Location.y, -0.03981186, EPSILON);
assertEquals(boosterFin1Location.z, -0.00996453, EPSILON);
final InstanceContext boosterFinContext2 = finContextList.get(5);
assertThat(boosterFinContext2.component.getClass(), equalTo(TrapezoidFinSet.class));
assertThat(boosterFinContext2.instanceNumber, equalTo(2));
final Coordinate boosterFin2Location = boosterFinContext2.getLocation();
assertEquals(boosterFin2Location.x, 1.044, EPSILON);
assertEquals(boosterFin2Location.y, -0.08696453, EPSILON);
assertEquals(boosterFin2Location.z, 0.03718814, EPSILON);
}
}
}
}
}

View File

@ -7,7 +7,6 @@ import static org.junit.Assert.assertThat;
import org.junit.Test;
import net.sf.openrocket.aerodynamics.FlightConditions;
import net.sf.openrocket.rocketcomponent.position.AngleMethod;
import net.sf.openrocket.rocketcomponent.position.RadiusMethod;
import net.sf.openrocket.util.Coordinate;
@ -35,12 +34,12 @@ public class RocketTest extends BaseTestCase {
FlightConfigurationId fcid4 = config4.getId();
assertThat("fcids should match: ", config1.getId().key, equalTo(fcid4.key));
assertThat("Configurations should be different: "+config1.toDebug()+"=?="+config4.toDebug(), config1.instanceNumber, not( config4.instanceNumber));
assertThat("Configurations should be different: "+config1.toDebug()+"=?="+config4.toDebug(), config1.configurationInstanceId, not( config4.configurationInstanceId));
FlightConfiguration config5 = rkt2.getFlightConfiguration(config2.getId());
FlightConfigurationId fcid5 = config5.getId();
assertThat("fcids should match: ", config2.getId(), equalTo(fcid5));
assertThat("Configurations should bef different match: "+config2.toDebug()+"=?="+config5.toDebug(), config2.instanceNumber, not( config5.instanceNumber));
assertThat("Configurations should bef different match: "+config2.toDebug()+"=?="+config5.toDebug(), config2.configurationInstanceId, not( config5.configurationInstanceId));
}
@ -260,7 +259,7 @@ public class RocketTest extends BaseTestCase {
loc = coreBody.getComponentLocations()[0];
assertEquals(coreBody.getName()+" offset is incorrect: ", 0.0, offset.x, EPSILON);
assertEquals(coreBody.getName()+" location is incorrect: ", 0.564, loc.x, EPSILON);
// ====== Booster Set Stage ======
// ====== ====== ======
ParallelStage boosters = (ParallelStage) coreBody.getChild(0);

View File

@ -4,6 +4,7 @@ import java.awt.Point;
import java.nio.ByteBuffer;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Map;
import java.util.Set;
import java.util.Vector;
@ -23,6 +24,8 @@ import net.sf.openrocket.gui.figure3d.geometry.Geometry.Surface;
import net.sf.openrocket.motor.Motor;
import net.sf.openrocket.motor.MotorConfiguration;
import net.sf.openrocket.rocketcomponent.FlightConfiguration;
import net.sf.openrocket.rocketcomponent.InstanceContext;
import net.sf.openrocket.rocketcomponent.InstanceMap;
import net.sf.openrocket.rocketcomponent.MotorMount;
import net.sf.openrocket.rocketcomponent.RocketComponent;
import net.sf.openrocket.util.Coordinate;
@ -159,39 +162,29 @@ public abstract class RocketRenderer {
private Collection<Geometry> getTreeGeometry( FlightConfiguration config){
System.err.println(String.format("==== Building tree geometry ===="));
return getTreeGeometry("", new ArrayList<Geometry>(), config, config.getRocket(), Transformation.IDENTITY);
}
private Collection<Geometry> getTreeGeometry(String indent, Collection<Geometry> treeGeometry, FlightConfiguration config, RocketComponent comp, final Transformation parentTransform){
final int instanceCount = comp.getInstanceCount();
double[] instanceAngles = comp.getInstanceAngles();
Coordinate[] instanceLocations = comp.getInstanceLocations();
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()));
}
// input
final InstanceMap imap = config.getActiveInstances();
// output buffer
final Collection<Geometry> treeGeometry = new ArrayList<Geometry>();
for(Map.Entry<RocketComponent, ArrayList<InstanceContext>> entry: imap.entrySet() ) {
final RocketComponent comp = entry.getKey();
final ArrayList<InstanceContext> contextList = entry.getValue();
System.err.println(String.format("....[%s]", comp.getName()));
// iterate over the aggregated instances for the whole tree.
for( int instanceNumber = 0; instanceNumber < instanceCount; ++instanceNumber) {
Coordinate currentLocation = instanceLocations[instanceNumber];
final double currentAngle = instanceAngles[instanceNumber];
// System.err.println( String.format("%s[ %s ]", indent, comp.getName()));
// System.err.println( String.format("%s :: %12.8g / %12.8g / %12.8g (m) @ %8.4g (rads) ", indent, currentLocation.x, currentLocation.y, currentLocation.z, currentAngle ));
Transformation currentTransform = parentTransform
.applyTransformation( Transformation.getTranslationTransform( currentLocation))
.applyTransformation( Transformation.rotate_x( currentAngle ));
for(InstanceContext context: contextList ) {
System.err.println(String.format("........[% 2d] %s", context.instanceNumber, context.getLocation().toPreciseString()));
// recurse into inactive trees: allow active stages inside inactive stages
for(RocketComponent child: comp.getChildren()) {
getTreeGeometry(indent+" ", treeGeometry, config, child, currentTransform );
}
// System.err.println( String.format("%s[ %s ]", indent, comp.getName()));
// System.err.println( String.format("%s :: %12.8g / %12.8g / %12.8g (m) @ %8.4g (rads) ", indent, currentLocation.x, currentLocation.y, currentLocation.z, currentAngle ));
Geometry geom = cr.getComponentGeometry( comp, currentTransform );
geom.active = config.isComponentActive( comp );
treeGeometry.add( geom );
Geometry instanceGeometry = cr.getComponentGeometry( comp, context.transform );
instanceGeometry.active = context.active;
treeGeometry.add( instanceGeometry );
}
}
return treeGeometry;
}

View File

@ -58,7 +58,7 @@ public class PrintableNoseCone extends AbstractPrintable<NoseCone> {
*/
@Override
protected void draw(Graphics2D g2) {
RocketComponentShape[] compShapes = TransitionShapes.getShapesSide(target, Transformation.rotate_x(0d), new Coordinate(0,0,0), PrintUnit.METERS.toPoints(1));
RocketComponentShape[] compShapes = TransitionShapes.getShapesSide(target, Transformation.IDENTITY, PrintUnit.METERS.toPoints(1));
if (compShapes != null && compShapes.length > 0) {
Rectangle r = compShapes[0].shape.getBounds();

View File

@ -4,15 +4,12 @@ import java.awt.Shape;
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(
RocketComponent component,
Transformation transformation,
Coordinate componentAbsoluteLocation){
public static RocketComponentShape[] getShapesSide( final RocketComponent component, final Transformation transformation) {
BodyTube tube = (BodyTube)component;
@ -20,22 +17,19 @@ public class BodyTubeShapes extends RocketComponentShape {
double radius = tube.getOuterRadius();
Shape[] s = new Shape[1];
s[0] = TubeShapes.getShapesSide( transformation, componentAbsoluteLocation, length, radius );
s[0] = TubeShapes.getShapesSide( transformation, length, radius );
return RocketComponentShape.toArray(s, component);
}
public static RocketComponentShape[] getShapesBack(
RocketComponent component,
Transformation transformation,
Coordinate componentAbsoluteLocation) {
public static RocketComponentShape[] getShapesBack( final RocketComponent component, final Transformation transformation) {
BodyTube tube = (BodyTube)component;
double radius = tube.getOuterRadius();
Shape[] s = new Shape[1];
s[0] = TubeShapes.getShapesBack( transformation, componentAbsoluteLocation, radius);
s[0] = TubeShapes.getShapesBack( transformation, radius);
return RocketComponentShape.toArray(s, component);
}

View File

@ -6,7 +6,6 @@ import java.util.ArrayList;
import net.sf.openrocket.rocketcomponent.FinSet;
import net.sf.openrocket.rocketcomponent.RocketComponent;
import net.sf.openrocket.rocketcomponent.TrapezoidFinSet;
import net.sf.openrocket.util.Coordinate;
import net.sf.openrocket.util.MathUtil;
import net.sf.openrocket.util.Transformation;
@ -15,11 +14,10 @@ import net.sf.openrocket.util.Transformation;
public class FinSetShapes extends RocketComponentShape {
public static RocketComponentShape[] getShapesSide(RocketComponent component,
Transformation transformation,
Coordinate instanceAbsoluteLocation ){
public static RocketComponentShape[] getShapesSide( final RocketComponent component,
final Transformation transformation){
final FinSet finset = (FinSet) component;
// this supplied transformation includes:
// - baseRotationTransformation
// - mount-radius transformtion
@ -47,40 +45,37 @@ public class FinSetShapes extends RocketComponentShape {
ArrayList<RocketComponentShape> shapeList = new ArrayList<>();
// Make fin polygon
shapeList.add(new RocketComponentShape(generatePath(instanceAbsoluteLocation, finPoints), finset));
shapeList.add(new RocketComponentShape(generatePath(finPoints), finset));
// Make fin polygon
shapeList.add(new RocketComponentShape(generatePath(instanceAbsoluteLocation, tabPoints), finset));
shapeList.add(new RocketComponentShape(generatePath(tabPoints), finset));
// Make fin polygon
shapeList.add(new RocketComponentShape(generatePath(instanceAbsoluteLocation, rootPoints), finset));
shapeList.add(new RocketComponentShape(generatePath(rootPoints), finset));
return shapeList.toArray(new RocketComponentShape[0]);
}
public static RocketComponentShape[] getShapesBack(
RocketComponent component,
Transformation transformation,
Coordinate location) {
public static RocketComponentShape[] getShapesBack( final RocketComponent component, final Transformation transformation) {
FinSet finset = (FinSet) component;
Shape[] toReturn;
if (MathUtil.equals(finset.getCantAngle(), 0)) {
toReturn = uncantedShapesBack(finset, transformation, location);
toReturn = uncantedShapesBack(finset, transformation);
} else {
toReturn = cantedShapesBack(finset, transformation, location);
toReturn = cantedShapesBack(finset, transformation);
}
return RocketComponentShape.toArray(toReturn, finset);
}
private static Path2D.Float generatePath(final Coordinate c0, final Coordinate[] points){
private static Path2D.Float generatePath(final Coordinate[] points){
Path2D.Float finShape = new Path2D.Float();
for( int i = 0; i < points.length; i++){
Coordinate curPoint = c0.add(points[i]);
Coordinate curPoint = points[i];
if (i == 0)
finShape.moveTo(curPoint.x, curPoint.y);
else
@ -90,8 +85,7 @@ public class FinSetShapes extends RocketComponentShape {
}
private static Shape[] uncantedShapesBack(FinSet finset,
Transformation transformation,
Coordinate finFront) {
Transformation transformation) {
double thickness = finset.getThickness();
double height = finset.getSpan();
@ -110,13 +104,13 @@ public class FinSetShapes extends RocketComponentShape {
Coordinate a;
Path2D.Double p = new Path2D.Double();
a = finFront.add( c[0] );
a = c[0];
p.moveTo(a.z, a.y);
a = finFront.add( c[1] );
a = c[1];
p.lineTo(a.z, a.y);
a = finFront.add( c[2] );
a = c[2];
p.lineTo(a.z, a.y);
a = finFront.add( c[3] );
a = c[3];
p.lineTo(a.z, a.y);
p.closePath();
@ -126,8 +120,7 @@ public class FinSetShapes extends RocketComponentShape {
// TODO: LOW: Jagged shapes from back draw incorrectly.
private static Shape[] cantedShapesBack(FinSet finset,
Transformation transformation,
Coordinate location) {
Transformation transformation) {
int i;
int fins = finset.getFinCount();
double thickness = finset.getThickness();
@ -179,15 +172,15 @@ public class FinSetShapes extends RocketComponentShape {
s = new Shape[fins*2];
for (int fin=0; fin<fins; fin++) {
s[2*fin] = makePolygonBack(sidePoints,finset,transformation, location);
s[2*fin+1] = makePolygonBack(backPoints,finset,transformation, location);
s[2*fin] = makePolygonBack(sidePoints,finset,transformation);
s[2*fin+1] = makePolygonBack(backPoints,finset,transformation);
}
} else {
s = new Shape[fins];
for (int fin=0; fin<fins; fin++) {
s[fin] = makePolygonBack(sidePoints,finset,transformation, location);
s[fin] = makePolygonBack(sidePoints,finset,transformation);
}
}
@ -195,11 +188,11 @@ public class FinSetShapes extends RocketComponentShape {
return s;
}
private static Shape makePolygonBack(Coordinate[] array, FinSet finset,
Transformation t, Coordinate location) {
private static Shape makePolygonBack(Coordinate[] array, FinSet finset, final Transformation t) {
Path2D.Float p;
Coordinate compCenter = location;
Coordinate compCenter = t.transform(Coordinate.ZERO);
// Make polygon
p = new Path2D.Float();
for (int i=0; i < array.length; i++) {

View File

@ -10,32 +10,26 @@ import net.sf.openrocket.rocketcomponent.RocketComponent;
public class LaunchLugShapes extends RocketComponentShape {
public static RocketComponentShape[] getShapesSide(
RocketComponent component,
Transformation transformation,
Coordinate instanceAbsoluteLocation) {
public static RocketComponentShape[] getShapesSide( final RocketComponent component, final Transformation transformation) {
LaunchLug lug = (LaunchLug)component;
double length = lug.getLength();
double radius = lug.getOuterRadius();
Shape[] s = new Shape[]{
TubeShapes.getShapesSide( transformation, instanceAbsoluteLocation, length, radius )
TubeShapes.getShapesSide( transformation, length, radius )
};
return RocketComponentShape.toArray(s, component);
}
public static RocketComponentShape[] getShapesBack(
RocketComponent component,
Transformation transformation,
Coordinate instanceAbsoluteLocation) {
public static RocketComponentShape[] getShapesBack( final RocketComponent component, final Transformation transformation) {
LaunchLug lug = (LaunchLug)component;
double radius = lug.getOuterRadius();
Shape[] s = new Shape[]{TubeShapes.getShapesBack( transformation, instanceAbsoluteLocation, radius)};
Shape[] s = new Shape[]{TubeShapes.getShapesBack( transformation, radius)};
return RocketComponentShape.toArray(s, component);
}

View File

@ -8,6 +8,9 @@ import java.awt.geom.Rectangle2D;
import java.awt.geom.RoundRectangle2D;
import java.util.Random;
import net.sf.openrocket.rocketcomponent.MassComponent;
import net.sf.openrocket.rocketcomponent.MassObject;
import net.sf.openrocket.rocketcomponent.RocketComponent;
import net.sf.openrocket.util.Coordinate;
import net.sf.openrocket.util.MathUtil;
import net.sf.openrocket.util.Transformation;
@ -15,22 +18,19 @@ import net.sf.openrocket.util.Transformation;
public class MassComponentShapes extends RocketComponentShape {
public static RocketComponentShape[] getShapesSide(
net.sf.openrocket.rocketcomponent.RocketComponent component,
Transformation transformation,
Coordinate componentAbsoluteLocation) {
public static RocketComponentShape[] getShapesSide( final RocketComponent component, final Transformation transformation) {
net.sf.openrocket.rocketcomponent.MassObject tube = (net.sf.openrocket.rocketcomponent.MassObject)component;
MassObject tube = (net.sf.openrocket.rocketcomponent.MassObject)component;
net.sf.openrocket.rocketcomponent.MassComponent.MassComponentType type = ((net.sf.openrocket.rocketcomponent.MassComponent)component).getMassComponentType();
MassComponent.MassComponentType type = ((MassComponent)component).getMassComponentType();
double length = tube.getLength();
double radius = tube.getRadius();
double arc = Math.min(length, 2*radius) * 0.7;
Coordinate start = transformation.transform( componentAbsoluteLocation);
Shape[] s = new Shape[1];
s[0] = new RoundRectangle2D.Double(start.x, (start.y-radius), length, 2*radius, arc, arc);
final Coordinate start = transformation.transform(Coordinate.ZERO);
Shape[] s = {new RoundRectangle2D.Double(start.x, (start.y-radius), length, 2*radius, arc, arc)};
switch (type) {
case ALTIMETER:
@ -61,21 +61,16 @@ public class MassComponentShapes extends RocketComponentShape {
}
public static RocketComponentShape[] getShapesBack(
net.sf.openrocket.rocketcomponent.RocketComponent component,
Transformation transformation,
Coordinate componentAbsoluteLocation) {
public static RocketComponentShape[] getShapesBack( final RocketComponent component, final Transformation transformation) {
net.sf.openrocket.rocketcomponent.MassObject tube = (net.sf.openrocket.rocketcomponent.MassObject)component;
double or = tube.getRadius();
Coordinate[] start = new Coordinate[]{transformation.transform( componentAbsoluteLocation )};
Shape[] s = new Shape[start.length];
for (int i=0; i < start.length; i++) {
s[i] = new Ellipse2D.Double((start[i].z-or),(start[i].y-or),2*or,2*or);
}
final Coordinate start = transformation.transform(Coordinate.ZERO);
Shape[] s = {new Ellipse2D.Double((start.z-or),(start.y-or),2*or,2*or)};
return RocketComponentShape.toArray(s, component);
}

View File

@ -4,48 +4,40 @@ import java.awt.Shape;
import java.awt.geom.Ellipse2D;
import java.awt.geom.RoundRectangle2D;
import net.sf.openrocket.rocketcomponent.MassObject;
import net.sf.openrocket.rocketcomponent.RocketComponent;
import net.sf.openrocket.util.Coordinate;
import net.sf.openrocket.util.Transformation;
public class MassObjectShapes extends RocketComponentShape {
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;
public static RocketComponentShape[] getShapesSide( final RocketComponent component, final Transformation transformation) {
MassObject tube = (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(instanceOffset));
Shape[] s = new Shape[start.length];
for (int i=0; i < start.length; i++) {
s[i] = new RoundRectangle2D.Double(start[i].x,(start[i].y-radius),
length,2*radius,arc,arc);
}
Coordinate start = transformation.transform(Coordinate.ZERO);
Shape[] s = {new RoundRectangle2D.Double(start.x, (start.y-radius), length, 2*radius, arc, arc)};
return RocketComponentShape.toArray(s, component);
}
public static RocketComponentShape[] getShapesBack(
net.sf.openrocket.rocketcomponent.RocketComponent component,
Transformation transformation,
Coordinate instanceOffset) {
public static RocketComponentShape[] getShapesBack( final RocketComponent component, final Transformation transformation) {
net.sf.openrocket.rocketcomponent.MassObject tube = (net.sf.openrocket.rocketcomponent.MassObject)component;
MassObject tube = (MassObject)component;
double or = tube.getRadius();
Coordinate[] start = transformation.transform(tube.toAbsolute(instanceOffset));
final Coordinate start = transformation.transform(Coordinate.ZERO);
Shape[] s = new Shape[start.length];
for (int i=0; i < start.length; i++) {
s[i] = new Ellipse2D.Double((start[i].z-or),(start[i].y-or),2*or,2*or);
}
Shape[] s = {new Ellipse2D.Double((start.z-or), (start.y-or), 2*or, 2*or)};
return RocketComponentShape.toArray(s, component);
}

View File

@ -1,5 +1,6 @@
package net.sf.openrocket.gui.rocketfigure;
import net.sf.openrocket.rocketcomponent.RocketComponent;
import net.sf.openrocket.util.Coordinate;
import net.sf.openrocket.util.Transformation;
@ -12,36 +13,31 @@ import java.awt.geom.RoundRectangle2D;
public class ParachuteShapes extends RocketComponentShape {
public static RocketComponentShape[] getShapesSide(
net.sf.openrocket.rocketcomponent.RocketComponent component,
Transformation transformation,
Coordinate componentAbsoluteLocation) {
public static RocketComponentShape[] getShapesSide( final RocketComponent component, final 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 = new Coordinate[]{transformation.transform( componentAbsoluteLocation)};
Coordinate start = transformation.transform( Coordinate.ZERO);
Shape[] s = new Shape[start.length];
for (int i=0; i < start.length; i++) {
s[i] = new RoundRectangle2D.Double(start[i].x, (start[i].y-radius), length, 2*radius, arc, arc);
}
Shape[] s = new Shape[1];
s[0] = new RoundRectangle2D.Double(start.x, (start.y-radius), length, 2*radius, arc, arc);
return RocketComponentShape.toArray( addSymbol(s), component);
}
public static RocketComponentShape[] getShapesBack(
net.sf.openrocket.rocketcomponent.RocketComponent component,
Transformation transformation,
Coordinate instanceOffset) {
public static RocketComponentShape[] getShapesBack( final RocketComponent component, final Transformation transformation) {
net.sf.openrocket.rocketcomponent.MassObject tube = (net.sf.openrocket.rocketcomponent.MassObject)component;
double or = tube.getRadius();
Coordinate[] start = transformation.transform(tube.toAbsolute(instanceOffset));
Coordinate[] start = transformation.transform(tube.toAbsolute(Coordinate.ZERO));
Shape[] s = new Shape[start.length];
for (int i=0; i < start.length; i++) {

View File

@ -14,11 +14,8 @@ import net.sf.openrocket.util.Transformation;
public class RailButtonShapes extends RocketComponentShape {
public static RocketComponentShape[] getShapesSide(
RocketComponent component,
Transformation transformation,
Coordinate instanceAbsoluteLocation) {
public static RocketComponentShape[] getShapesSide( final RocketComponent component, final Transformation transformation) {
RailButton btn = (RailButton)component;
final double rotation_rad = btn.getAngleOffset();
@ -36,6 +33,11 @@ public class RailButtonShapes extends RocketComponentShape {
final double innerHeightcos = innerHeight*cosr;
final double flangeHeightcos = flangeHeight*cosr;
final Coordinate instanceAbsoluteLocation = transformation.transform(Coordinate.ZERO);
System.err.println(String.format("Generating Shapes for RailButtons..."));
System.err.println(String.format(" @ %s", instanceAbsoluteLocation));
Path2D.Double path = new Path2D.Double();
{// central pillar
@ -51,7 +53,7 @@ public class RailButtonShapes extends RocketComponentShape {
path.append( new Ellipse2D.Double( lowerLeft.x, (lowerLeft.y+baseHeightcos), drawWidth, drawHeight), false);
}
{// inner
{// inner flange
final double drawWidth = innerDiameter;
final double drawHeight = innerDiameter*sinr;
final Point2D.Double center = new Point2D.Double( instanceAbsoluteLocation.x, instanceAbsoluteLocation.y + baseHeightcos);
@ -80,12 +82,9 @@ public class RailButtonShapes extends RocketComponentShape {
}
public static RocketComponentShape[] getShapesBack(
net.sf.openrocket.rocketcomponent.RocketComponent component,
Transformation transformation,
Coordinate instanceOffset) {
public static RocketComponentShape[] getShapesBack( final RocketComponent component, final Transformation transformation) {
net.sf.openrocket.rocketcomponent.RailButton btn = (net.sf.openrocket.rocketcomponent.RailButton)component;
RailButton btn = (RailButton)component;
final double rotation_rad = btn.getAngleOffset();
final double sinr = Math.sin(rotation_rad);
@ -98,7 +97,8 @@ 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());
Coordinate[] inst = {transformation.transform(Coordinate.ZERO)};
Shape[] s = new Shape[inst.length];
for (int i=0; i < inst.length; i++) {

View File

@ -2,19 +2,16 @@ 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.rocketcomponent.RingComponent;
import net.sf.openrocket.rocketcomponent.RocketComponent;
import net.sf.openrocket.util.Transformation;
public class RingComponentShapes extends RocketComponentShape {
public static RocketComponentShape[] getShapesSide(
net.sf.openrocket.rocketcomponent.RocketComponent component,
Transformation transformation,
Coordinate instanceAbsoluteLocation) {
public static RocketComponentShape[] getShapesSide( final RocketComponent component, final Transformation transformation) {
net.sf.openrocket.rocketcomponent.RingComponent tube = (net.sf.openrocket.rocketcomponent.RingComponent)component;
Shape[] s;
@ -26,24 +23,22 @@ public class RingComponentShapes extends RocketComponentShape {
if ((outerRadius-innerRadius >= 0.0012) && (innerRadius > 0)) {
// Draw outer and inner
s = new Shape[] {
TubeShapes.getShapesSide(transformation, instanceAbsoluteLocation, length, outerRadius),
TubeShapes.getShapesSide(transformation, instanceAbsoluteLocation, length, innerRadius)
TubeShapes.getShapesSide(transformation, length, outerRadius),
TubeShapes.getShapesSide(transformation, length, innerRadius)
};
} else {
// Draw only outer
s = new Shape[] {
TubeShapes.getShapesSide(transformation, instanceAbsoluteLocation, length, outerRadius)
TubeShapes.getShapesSide(transformation, length, outerRadius)
};
}
return RocketComponentShape.toArray( s, component);
}
public static RocketComponentShape[] getShapesBack(
net.sf.openrocket.rocketcomponent.RocketComponent component,
Transformation transformation,
Coordinate instanceAbsoluteLocation) {
net.sf.openrocket.rocketcomponent.RingComponent tube = (net.sf.openrocket.rocketcomponent.RingComponent)component;
public static RocketComponentShape[] getShapesBack( final RocketComponent component, final Transformation transformation) {
RingComponent tube = (net.sf.openrocket.rocketcomponent.RingComponent)component;
Shape[] s;
double outerRadius = tube.getOuterRadius();
@ -51,12 +46,12 @@ public class RingComponentShapes extends RocketComponentShape {
if ((outerRadius-innerRadius >= 0.0012) && (innerRadius > 0)) {
s = new Shape[] {
TubeShapes.getShapesBack(transformation, instanceAbsoluteLocation, outerRadius),
TubeShapes.getShapesBack(transformation, instanceAbsoluteLocation, innerRadius)
TubeShapes.getShapesBack(transformation, outerRadius),
TubeShapes.getShapesBack(transformation, innerRadius)
};
}else {
s = new Shape[] {
TubeShapes.getShapesBack(transformation, instanceAbsoluteLocation, outerRadius)
TubeShapes.getShapesBack(transformation, outerRadius)
};
}

View File

@ -3,10 +3,8 @@ 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;
@ -51,20 +49,15 @@ public class RocketComponentShape {
}
public static RocketComponentShape[] getShapesSide(
net.sf.openrocket.rocketcomponent.RocketComponent component,
Transformation transformation,
Coordinate instanceOffset) {
public static RocketComponentShape[] getShapesSide( final RocketComponent component, final Transformation transformation) {
// 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
public static RocketComponentShape[] getShapesBack( final RocketComponent component, final Transformation transformation) {
// no-op
Application.getExceptionHandler().handleErrorCondition("ERROR: RocketComponent.getShapesBack called with "
+component);
return new RocketComponentShape[0];

View File

@ -1,5 +1,6 @@
package net.sf.openrocket.gui.rocketfigure;
import net.sf.openrocket.rocketcomponent.RocketComponent;
import net.sf.openrocket.util.Coordinate;
import net.sf.openrocket.util.Transformation;
@ -11,10 +12,8 @@ import java.awt.geom.RoundRectangle2D;
public class ShockCordShapes extends RocketComponentShape {
public static RocketComponentShape[] getShapesSide(
net.sf.openrocket.rocketcomponent.RocketComponent component,
Transformation transformation,
Coordinate componentAbsoluteLocation) {
public static RocketComponentShape[] getShapesSide( final RocketComponent component, final Transformation transformation) {
net.sf.openrocket.rocketcomponent.MassObject massObj = (net.sf.openrocket.rocketcomponent.MassObject)component;
@ -22,8 +21,7 @@ public class ShockCordShapes extends RocketComponentShape {
double radius = massObj.getRadius();
double arc = Math.min(length, 2*radius) * 0.7;
Coordinate start = transformation.transform( componentAbsoluteLocation);
Coordinate start = transformation.transform(Coordinate.ZERO);
Shape[] s = new Shape[1];
s[0] = new RoundRectangle2D.Double(start.x,(start.y-radius),
length,2*radius,arc,arc);
@ -32,17 +30,15 @@ public class ShockCordShapes extends RocketComponentShape {
}
public static RocketComponentShape[] getShapesBack(
net.sf.openrocket.rocketcomponent.RocketComponent component,
Transformation transformation,
Coordinate componentAbsoluteLocation) {
public static RocketComponentShape[] getShapesBack( final RocketComponent component, final Transformation transformation) {
net.sf.openrocket.rocketcomponent.MassObject tube = (net.sf.openrocket.rocketcomponent.MassObject)component;
double or = tube.getRadius();
Shape[] s = new Shape[1];
Coordinate start = componentAbsoluteLocation;
Coordinate start = transformation.transform(Coordinate.ZERO);
s[0] = new Ellipse2D.Double((start.z-or),(start.y-or),2*or,2*or);
// Coordinate[] start = transformation.transform(tube.toAbsolute(instanceOffset));

View File

@ -1,5 +1,6 @@
package net.sf.openrocket.gui.rocketfigure;
import net.sf.openrocket.rocketcomponent.RocketComponent;
import net.sf.openrocket.util.Coordinate;
import net.sf.openrocket.util.Transformation;
@ -11,10 +12,7 @@ import java.awt.geom.RoundRectangle2D;
public class StreamerShapes extends RocketComponentShape {
public static RocketComponentShape[] getShapesSide(
net.sf.openrocket.rocketcomponent.RocketComponent component,
Transformation transformation,
Coordinate componentAbsoluteLocation ) {
public static RocketComponentShape[] getShapesSide( final RocketComponent component, final Transformation transformation) {
net.sf.openrocket.rocketcomponent.MassObject massObj = (net.sf.openrocket.rocketcomponent.MassObject)component;
@ -23,7 +21,7 @@ public class StreamerShapes extends RocketComponentShape {
double arc = Math.min(length, 2*radius) * 0.7;
Shape[] s = new Shape[1];
Coordinate frontCenter = componentAbsoluteLocation;
Coordinate frontCenter = transformation.transform(Coordinate.ZERO);
s[0] = new RoundRectangle2D.Double((frontCenter.x),(frontCenter.y-radius),
length,2*radius,arc,arc);
@ -37,16 +35,14 @@ public class StreamerShapes extends RocketComponentShape {
}
public static RocketComponentShape[] getShapesBack(
net.sf.openrocket.rocketcomponent.RocketComponent component,
Transformation transformation,
Coordinate componentAbsoluteLocation) {
public static RocketComponentShape[] getShapesBack( final RocketComponent component, final Transformation transformation) {
net.sf.openrocket.rocketcomponent.MassObject tube = (net.sf.openrocket.rocketcomponent.MassObject)component;
double or = tube.getRadius();
Shape[] s = new Shape[1];
Coordinate center = componentAbsoluteLocation;
Coordinate center = transformation.transform(Coordinate.ZERO);
s[0] = new Ellipse2D.Double((center.z-or),(center.y-or),2*or,2*or);
// Coordinate[] start = transformation.transform(tube.toAbsolute(instanceOffset));

View File

@ -1,5 +1,6 @@
package net.sf.openrocket.gui.rocketfigure;
import net.sf.openrocket.rocketcomponent.RocketComponent;
import net.sf.openrocket.rocketcomponent.SymmetricComponent;
import net.sf.openrocket.util.Coordinate;
import net.sf.openrocket.util.MathUtil;
@ -17,10 +18,8 @@ public class SymmetricComponentShapes extends RocketComponentShape {
// TODO: LOW: Uses only first component of cluster (not currently clusterable)
public static RocketComponentShape[] getShapesSide(
net.sf.openrocket.rocketcomponent.RocketComponent component,
Transformation transformation,
Coordinate componentAbsoluteLocation) {
public static RocketComponentShape[] getShapesSide( final RocketComponent component, final Transformation transformation) {
SymmetricComponent c = (SymmetricComponent) component;
@ -79,7 +78,7 @@ public class SymmetricComponentShapes extends RocketComponentShape {
//System.out.println("here");
final int len = points.size();
Coordinate nose = componentAbsoluteLocation;
Coordinate nose = transformation.transform(Coordinate.ZERO);
// TODO: LOW: curved path instead of linear
Path2D.Double path = new Path2D.Double();

View File

@ -12,24 +12,20 @@ import java.awt.geom.Path2D;
public class TransitionShapes extends RocketComponentShape {
// TODO: LOW: Uses only first component of cluster (not currently clusterable).
public static RocketComponentShape[] getShapesSide(
RocketComponent component,
Transformation transformation,
Coordinate instanceLocation) {
return getShapesSide(component, transformation, instanceLocation, 1.0);
public static RocketComponentShape[] getShapesSide( final RocketComponent component, final Transformation transformation) {
return getShapesSide(component, transformation, 1.0);
}
public static RocketComponentShape[] getShapesSide(
RocketComponent component,
Transformation transformation,
Coordinate instanceAbsoluteLocation,
final double scaleFactor) {
final RocketComponent component,
final Transformation transformation,
final double scaleFactor) {
Transition transition = (Transition)component;
final Coordinate instanceAbsoluteLocation = transformation.transform(Coordinate.ZERO);
RocketComponentShape[] mainShapes;
// Simpler shape for conical transition, others use the method from SymmetricComponent
@ -49,27 +45,28 @@ public class TransitionShapes extends RocketComponentShape {
mainShapes = new RocketComponentShape[] { new RocketComponentShape( path, component) };
} else {
mainShapes = SymmetricComponentShapes.getShapesSide(component, transformation, instanceAbsoluteLocation);
mainShapes = SymmetricComponentShapes.getShapesSide(component, transformation);
}
Shape foreShoulder=null, aftShoulder=null;
int arrayLength = mainShapes.length;
if (transition.getForeShoulderLength() > 0.0005) {
Coordinate foreTransitionShoulderCenter = instanceAbsoluteLocation.sub( transition.getForeShoulderLength(), 0, 0);
final Coordinate frontCenter = foreTransitionShoulderCenter; //transformation.transform( foreTransitionShoulderCenter);
final double length = transition.getForeShoulderLength();
final double radius = transition.getForeShoulderRadius();
final double shoulderLength = transition.getForeShoulderLength();
final double shoulderRadius = transition.getForeShoulderRadius();
final Transformation offsetTransform = Transformation.getTranslationTransform(-transition.getForeShoulderLength(), 0, 0);
final Transformation foreShoulderTransform = transformation.applyTransformation(offsetTransform);
foreShoulder = TubeShapes.getShapesSide( transformation, frontCenter, length, radius);
foreShoulder = TubeShapes.getShapesSide( foreShoulderTransform, shoulderLength, shoulderRadius);
arrayLength++;
}
if (transition.getAftShoulderLength() > 0.0005) {
Coordinate aftTransitionShoulderCenter = instanceAbsoluteLocation.add( transition.getLength(), 0, 0);
final Coordinate frontCenter = aftTransitionShoulderCenter; //transformation.transform( aftTransitionShoulderCenter );
final double length = transition.getAftShoulderLength();
final double radius = transition.getAftShoulderRadius();
aftShoulder = TubeShapes.getShapesSide(transformation, frontCenter, length, radius);
final double shoulderLength = transition.getAftShoulderLength();
final double shoulderRadius = transition.getAftShoulderRadius();
final Transformation offsetTransform = Transformation.getTranslationTransform(transition.getLength(), 0, 0);
final Transformation aftShoulderTransform = transformation.applyTransformation(offsetTransform);
aftShoulder = TubeShapes.getShapesSide(aftShoulderTransform, shoulderLength, shoulderRadius);
arrayLength++;
}
if (foreShoulder==null && aftShoulder==null)
@ -92,17 +89,14 @@ public class TransitionShapes extends RocketComponentShape {
}
public static RocketComponentShape[] getShapesBack(
net.sf.openrocket.rocketcomponent.RocketComponent component,
Transformation transformation,
Coordinate componentAbsoluteLocation) {
public static RocketComponentShape[] getShapesBack( final RocketComponent component, final Transformation transformation) {
net.sf.openrocket.rocketcomponent.Transition transition = (net.sf.openrocket.rocketcomponent.Transition)component;
Transition transition = (net.sf.openrocket.rocketcomponent.Transition)component;
double r1 = transition.getForeRadius();
double r2 = transition.getAftRadius();
Coordinate center = componentAbsoluteLocation;
final Coordinate center = transformation.transform(Coordinate.ZERO);
Shape[] s = new Shape[2];
s[0] = new Ellipse2D.Double((center.z-r1),(center.y-r1),2*r1,2*r1);

View File

@ -4,18 +4,17 @@ import java.awt.Shape;
import java.awt.geom.Ellipse2D;
import java.awt.geom.Rectangle2D;
import net.sf.openrocket.rocketcomponent.RocketComponent;
import net.sf.openrocket.rocketcomponent.TubeFinSet;
import net.sf.openrocket.util.Coordinate;
import net.sf.openrocket.util.Transformation;
public class TubeFinSetShapes extends RocketComponentShape {
public static RocketComponentShape[] getShapesSide(
net.sf.openrocket.rocketcomponent.RocketComponent component,
Transformation transformation,
Coordinate componentAbsoluteLocation) {
public static RocketComponentShape[] getShapesSide( final RocketComponent component, final Transformation transformation) {
net.sf.openrocket.rocketcomponent.TubeFinSet finset = (net.sf.openrocket.rocketcomponent.TubeFinSet)component;
TubeFinSet finset = (net.sf.openrocket.rocketcomponent.TubeFinSet)component;
int fins = finset.getFinCount();
double length = finset.getLength();
@ -47,12 +46,9 @@ public class TubeFinSetShapes extends RocketComponentShape {
}
public static RocketComponentShape[] getShapesBack(
net.sf.openrocket.rocketcomponent.RocketComponent component,
Transformation transformation,
Coordinate componentAbsoluteLocation) {
public static RocketComponentShape[] getShapesBack( final RocketComponent component, final Transformation transformation) {
net.sf.openrocket.rocketcomponent.TubeFinSet finset = (net.sf.openrocket.rocketcomponent.TubeFinSet)component;
TubeFinSet finset = (net.sf.openrocket.rocketcomponent.TubeFinSet)component;
int fins = finset.getFinCount();
double outerradius = finset.getOuterRadius();

View File

@ -10,21 +10,19 @@ 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 ){
public static Shape getShapesSide( final Transformation transformation, final double length, final double radius ){
final Coordinate instanceAbsoluteLocation = transformation.transform(Coordinate.ZERO);
return new Rectangle2D.Double((instanceAbsoluteLocation.x), //x - the X coordinate of the upper-left corner of the newly constructed Rectangle2D
(instanceAbsoluteLocation.y-radius), // y - the Y coordinate of the upper-left corner of the newly constructed Rectangle2D
length, // w - the width of the newly constructed Rectangle2D
2*radius); // h - the height of the newly constructed Rectangle2D
}
public static Shape getShapesBack(
Transformation transformation,
Coordinate instanceAbsoluteLocation,
final double radius ) {
public static Shape getShapesBack( final Transformation transformation, final double radius ) {
final Coordinate instanceAbsoluteLocation = transformation.transform(Coordinate.ZERO);
return new Ellipse2D.Double((instanceAbsoluteLocation.z-radius), (instanceAbsoluteLocation.y-radius), 2*radius, 2*radius);
}

View File

@ -15,22 +15,21 @@ import java.awt.geom.NoninvertibleTransformException;
import java.awt.geom.Point2D;
import java.awt.geom.Rectangle2D;
import java.util.ArrayList;
import java.util.Collection;
import java.util.LinkedHashSet;
import java.util.Map.Entry;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import net.sf.openrocket.gui.figureelements.FigureElement;
import net.sf.openrocket.gui.rocketfigure.RocketComponentShape;
import net.sf.openrocket.gui.scalefigure.RocketPanel.VIEW_TYPE;
import net.sf.openrocket.gui.util.ColorConversion;
import net.sf.openrocket.gui.util.SwingPreferences;
import net.sf.openrocket.motor.Motor;
import net.sf.openrocket.motor.MotorConfiguration;
import net.sf.openrocket.rocketcomponent.ComponentAssembly;
import net.sf.openrocket.rocketcomponent.FinSet;
import net.sf.openrocket.rocketcomponent.FlightConfiguration;
import net.sf.openrocket.rocketcomponent.InstanceContext;
import net.sf.openrocket.rocketcomponent.MotorMount;
import net.sf.openrocket.rocketcomponent.Rocket;
import net.sf.openrocket.rocketcomponent.RocketComponent;
@ -192,8 +191,7 @@ public class RocketFigure extends AbstractScaleFigure {
updateCanvasSize();
updateTransform();
figureShapes.clear();
updateShapeTree( this.figureShapes, rocket, this.axialRotation, Coordinate.ZERO);
updateShapes(this.figureShapes);
g2.transform(projection);
@ -336,60 +334,29 @@ public class RocketFigure extends AbstractScaleFigure {
return l.toArray(new RocketComponent[0]);
}
// NOTE: Recursive function
private ArrayList<RocketComponentShape> updateShapeTree(
ArrayList<RocketComponentShape> allShapes, // output parameter
final RocketComponent comp,
final Transformation parentTransform,
final Coordinate parentLocation){
private void updateShapes(ArrayList<RocketComponentShape> allShapes) {
// source input
final FlightConfiguration config = rocket.getSelectedConfiguration();
// allShapes is an output buffer -- it stores all the generated shapes
allShapes.clear();
for(Entry<RocketComponent, ArrayList<InstanceContext>> entry: config.getActiveInstances().entrySet() ) {
final RocketComponent comp = entry.getKey();
final ArrayList<InstanceContext> contextList = entry.getValue();
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] );
// if(FinSet.class.isAssignableFrom(comp.getClass())) {
// System.err.println(String.format("@%s: %s -- inst: [%d/%d]", comp.getClass().getSimpleName(), comp.getName(), index+1, instanceCount));
//
// // FlightConfiguration config = this.rocket.getSelectedConfiguration();
// // System.err.println(String.format(" -- stage: %d, active: %b, config: (%d) %s", comp.getStageNumber(), config.isComponentActive(comp), config.instanceNumber, config.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.rocket.getSelectedConfiguration().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
updateShapeTree( allShapes, child, currentTransform, currentLocation );
}
}
return allShapes;
for(InstanceContext context: contextList ) {
final Transformation currentTransform = this.axialRotation.applyTransformation(context.transform);
// generate shape for this component, if active
if( context.active ) {
allShapes = addThisShape( allShapes, this.currentViewType, comp, currentTransform);
}
}
}
}
/**
* Gets the shapes required to draw the component.
*
@ -401,12 +368,11 @@ public class RocketFigure extends AbstractScaleFigure {
ArrayList<RocketComponentShape> allShapes, // this is the output parameter
final RocketPanel.VIEW_TYPE viewType,
final RocketComponent component,
final Coordinate instanceOffset,
final Transformation transformation) {
Reflection.Method m;
if(( component instanceof Rocket)||( component instanceof ComponentAssembly )){
// no-op; no shapes here, either.
// no-op; no shapes here
return allShapes;
}
@ -414,12 +380,12 @@ public class RocketFigure extends AbstractScaleFigure {
switch (viewType) {
case SideView:
m = Reflection.findMethod(ROCKET_FIGURE_PACKAGE, component, ROCKET_FIGURE_SUFFIX, "getShapesSide",
RocketComponent.class, Transformation.class, Coordinate.class);
RocketComponent.class, Transformation.class);
break;
case BackView:
m = Reflection.findMethod(ROCKET_FIGURE_PACKAGE, component, ROCKET_FIGURE_SUFFIX, "getShapesBack",
RocketComponent.class, Transformation.class, Coordinate.class);
RocketComponent.class, Transformation.class);
break;
default:
@ -433,14 +399,13 @@ public class RocketFigure extends AbstractScaleFigure {
}
RocketComponentShape[] returnValue = (RocketComponentShape[]) m.invokeStatic(component, transformation, instanceOffset);
RocketComponentShape[] returnValue = (RocketComponentShape[]) m.invokeStatic(component, transformation);
for ( RocketComponentShape curShape : returnValue ){
allShapes.add( curShape );
}
return allShapes;
}
/**
* Gets the bounds of the drawn subject in Model-Space

View File

@ -620,7 +620,7 @@ public class RocketPanel extends JPanel implements TreeSelectionListener, Change
length = maxX - minX;
}
for (RocketComponent c : curConfig.getActiveComponents()) {
for (RocketComponent c : curConfig.getAllComponents()) {
if (c instanceof SymmetricComponent) {
double d1 = ((SymmetricComponent) c).getForeRadius() * 2;
double d2 = ((SymmetricComponent) c).getAftRadius() * 2;