Merge branch 'release-notes-b2' of https://github.com/neilweinstock/openrocket into release-notes-b2
This commit is contained in:
commit
4ef5a02322
Binary file not shown.
@ -96,6 +96,7 @@ FileHelper.ALL_DESIGNS_FILTER = All rocket designs (*.ork; *.rkt)
|
|||||||
FileHelper.OPENROCKET_DESIGN_FILTER = OpenRocket designs (*.ork)
|
FileHelper.OPENROCKET_DESIGN_FILTER = OpenRocket designs (*.ork)
|
||||||
FileHelper.ROCKSIM_DESIGN_FILTER = RockSim designs (*.rkt)
|
FileHelper.ROCKSIM_DESIGN_FILTER = RockSim designs (*.rkt)
|
||||||
FileHelper.OPEN_ROCKET_COMPONENT_FILTER = OpenRocket presets (*.orc)
|
FileHelper.OPEN_ROCKET_COMPONENT_FILTER = OpenRocket presets (*.orc)
|
||||||
|
FileHelper.PNG_FILTER = PNG image (*.png)
|
||||||
FileHelper.IMAGES = Image files
|
FileHelper.IMAGES = Image files
|
||||||
|
|
||||||
|
|
||||||
@ -1273,6 +1274,7 @@ TCMotorSelPan.btn.close = Close
|
|||||||
! PlotDialog
|
! PlotDialog
|
||||||
PlotDialog.CheckBox.Showdatapoints = Show data points
|
PlotDialog.CheckBox.Showdatapoints = Show data points
|
||||||
PlotDialog.lbl.Chart = left click drag to zoom area. mouse wheel to zoom. ctrl-mouse wheel to zoom x axis only. ctrl-left click drag to pan. right click drag to zoom dynamically.
|
PlotDialog.lbl.Chart = left click drag to zoom area. mouse wheel to zoom. ctrl-mouse wheel to zoom x axis only. ctrl-left click drag to pan. right click drag to zoom dynamically.
|
||||||
|
PlotDialog.btn.exportImage = Export Image
|
||||||
|
|
||||||
ComponentTree.ttip.massoverride = mass override
|
ComponentTree.ttip.massoverride = mass override
|
||||||
ComponentTree.ttip.cgoverride = cg override
|
ComponentTree.ttip.cgoverride = cg override
|
||||||
|
@ -64,6 +64,7 @@ public class FlightConfiguration implements FlightConfigurableParameter<FlightCo
|
|||||||
final protected HashMap<Integer, StageFlags> stages = new HashMap<Integer, StageFlags>();
|
final protected HashMap<Integer, StageFlags> stages = new HashMap<Integer, StageFlags>();
|
||||||
final protected HashMap<MotorConfigurationId, MotorConfiguration> motors = new HashMap<MotorConfigurationId, MotorConfiguration>();
|
final protected HashMap<MotorConfigurationId, MotorConfiguration> motors = new HashMap<MotorConfigurationId, MotorConfiguration>();
|
||||||
final private Collection<MotorConfiguration> activeMotors = new ArrayList<MotorConfiguration>();
|
final private Collection<MotorConfiguration> activeMotors = new ArrayList<MotorConfiguration>();
|
||||||
|
final private InstanceMap activeInstances = new InstanceMap();
|
||||||
|
|
||||||
private int boundsModID = -1;
|
private int boundsModID = -1;
|
||||||
private BoundingBox cachedBounds = new BoundingBox();
|
private BoundingBox cachedBounds = new BoundingBox();
|
||||||
@ -101,6 +102,7 @@ public class FlightConfiguration implements FlightConfigurableParameter<FlightCo
|
|||||||
|
|
||||||
updateStages();
|
updateStages();
|
||||||
updateMotors();
|
updateMotors();
|
||||||
|
updateActiveInstances();
|
||||||
}
|
}
|
||||||
|
|
||||||
public Rocket getRocket() {
|
public Rocket getRocket() {
|
||||||
@ -121,12 +123,14 @@ public class FlightConfiguration implements FlightConfigurableParameter<FlightCo
|
|||||||
cur.active = _active;
|
cur.active = _active;
|
||||||
}
|
}
|
||||||
updateMotors();
|
updateMotors();
|
||||||
|
updateActiveInstances();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void copyStages(FlightConfiguration other) {
|
public void copyStages(FlightConfiguration other) {
|
||||||
for (StageFlags cur : other.stages.values())
|
for (StageFlags cur : other.stages.values())
|
||||||
stages.put(cur.stageNumber, new StageFlags(cur.stageNumber, cur.active));
|
stages.put(cur.stageNumber, new StageFlags(cur.stageNumber, cur.active));
|
||||||
updateMotors();
|
updateMotors();
|
||||||
|
updateActiveInstances();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -137,6 +141,7 @@ public class FlightConfiguration implements FlightConfigurableParameter<FlightCo
|
|||||||
public void clearStage(final int stageNumber) {
|
public void clearStage(final int stageNumber) {
|
||||||
_setStageActive( stageNumber, false );
|
_setStageActive( stageNumber, false );
|
||||||
updateMotors();
|
updateMotors();
|
||||||
|
updateActiveInstances();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -163,6 +168,7 @@ public class FlightConfiguration implements FlightConfigurableParameter<FlightCo
|
|||||||
_setStageActive(i, true);
|
_setStageActive(i, true);
|
||||||
}
|
}
|
||||||
updateMotors();
|
updateMotors();
|
||||||
|
updateActiveInstances();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -174,6 +180,7 @@ public class FlightConfiguration implements FlightConfigurableParameter<FlightCo
|
|||||||
_setAllStages(false);
|
_setAllStages(false);
|
||||||
_setStageActive(stageNumber, true);
|
_setStageActive(stageNumber, true);
|
||||||
updateMotors();
|
updateMotors();
|
||||||
|
updateActiveInstances();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -196,9 +203,11 @@ public class FlightConfiguration implements FlightConfigurableParameter<FlightCo
|
|||||||
if ((0 <= stageNumber) && (stages.containsKey(stageNumber))) {
|
if ((0 <= stageNumber) && (stages.containsKey(stageNumber))) {
|
||||||
StageFlags flags = stages.get(stageNumber);
|
StageFlags flags = stages.get(stageNumber);
|
||||||
flags.active = !flags.active;
|
flags.active = !flags.active;
|
||||||
|
updateMotors();
|
||||||
|
updateActiveInstances();
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
updateMotors();
|
|
||||||
log.error("error: attempt to retrieve via a bad stage number: " + stageNumber);
|
log.error("error: attempt to retrieve via a bad stage number: " + stageNumber);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -286,21 +295,22 @@ public class FlightConfiguration implements FlightConfigurableParameter<FlightCo
|
|||||||
return toReturn;
|
return toReturn;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public InstanceMap getActiveInstances() {
|
||||||
|
return activeInstances;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Generates a read-only, instance-aware collection of the components for this rocket & configuration
|
* 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!
|
* TODO: swap in this function for the 'getActiveComponents() function, above; ONLY WHEN READY / MATURE!
|
||||||
*/
|
*/
|
||||||
public InstanceMap getActiveInstances() {
|
private void updateActiveInstances() {
|
||||||
InstanceMap contexts = new InstanceMap();
|
activeInstances.clear();
|
||||||
getActiveContextListAt( this.rocket, contexts, Transformation.IDENTITY);
|
getActiveContextListAt( this.rocket, activeInstances, Transformation.IDENTITY);
|
||||||
return contexts;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private InstanceMap getActiveContextListAt(final RocketComponent component, final InstanceMap results, final Transformation parentTransform ){
|
private InstanceMap getActiveContextListAt(final RocketComponent component, final InstanceMap results, final Transformation parentTransform ){
|
||||||
final boolean active = this.isComponentActive(component);
|
|
||||||
if (!active)
|
|
||||||
return results;
|
|
||||||
final int instanceCount = component.getInstanceCount();
|
final int instanceCount = component.getInstanceCount();
|
||||||
final Coordinate[] allOffsets = component.getInstanceOffsets();
|
final Coordinate[] allOffsets = component.getInstanceOffsets();
|
||||||
final double[] allAngles = component.getInstanceAngles();
|
final double[] allAngles = component.getInstanceAngles();
|
||||||
@ -314,9 +324,11 @@ public class FlightConfiguration implements FlightConfigurableParameter<FlightCo
|
|||||||
final Transformation angleTransform = Transformation.getAxialRotation(allAngles[currentInstanceNumber]);
|
final Transformation angleTransform = Transformation.getAxialRotation(allAngles[currentInstanceNumber]);
|
||||||
final Transformation currentTransform = componentTransform.applyTransformation(offsetTransform)
|
final Transformation currentTransform = componentTransform.applyTransformation(offsetTransform)
|
||||||
.applyTransformation(angleTransform);
|
.applyTransformation(angleTransform);
|
||||||
|
|
||||||
// constructs entry in-place
|
// constructs entry in-place if this component is active
|
||||||
results.emplace(component, active, currentInstanceNumber, currentTransform);
|
if (this.isComponentActive(component)) {
|
||||||
|
results.emplace(component, this.isComponentActive(component), currentInstanceNumber, currentTransform);
|
||||||
|
}
|
||||||
|
|
||||||
for(RocketComponent child : component.getChildren()) {
|
for(RocketComponent child : component.getChildren()) {
|
||||||
getActiveContextListAt(child, results, currentTransform);
|
getActiveContextListAt(child, results, currentTransform);
|
||||||
@ -401,6 +413,7 @@ public class FlightConfiguration implements FlightConfigurableParameter<FlightCo
|
|||||||
|
|
||||||
updateStages();
|
updateStages();
|
||||||
updateMotors();
|
updateMotors();
|
||||||
|
updateActiveInstances();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void updateStages() {
|
private void updateStages() {
|
||||||
@ -531,6 +544,7 @@ public class FlightConfiguration implements FlightConfigurableParameter<FlightCo
|
|||||||
public void update(){
|
public void update(){
|
||||||
updateStages();
|
updateStages();
|
||||||
updateMotors();
|
updateMotors();
|
||||||
|
updateActiveInstances();
|
||||||
}
|
}
|
||||||
|
|
||||||
/////////////// Helper methods ///////////////
|
/////////////// Helper methods ///////////////
|
||||||
@ -604,35 +618,12 @@ public class FlightConfiguration implements FlightConfigurableParameter<FlightCo
|
|||||||
}
|
}
|
||||||
|
|
||||||
for (InstanceContext context : contexts) {
|
for (InstanceContext context : contexts) {
|
||||||
/*
|
|
||||||
* If the instance is not active in the current context, then
|
|
||||||
* skip the bound calculations. This is mildly confusing since
|
|
||||||
* getActiveInstances() implies that it will only return the
|
|
||||||
* instances that are active, but it returns all instances and
|
|
||||||
* the context indicates if it is active or not.
|
|
||||||
*/
|
|
||||||
if (!context.active) {
|
|
||||||
// break out of per-instance loop.
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
componentBounds.update(instanceBounds.transform(context.transform));
|
componentBounds.update(instanceBounds.transform(context.transform));
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// Legacy Case: These components do not implement the BoxBounded Interface.
|
// Legacy Case: These components do not implement the BoxBounded Interface.
|
||||||
Collection<Coordinate> instanceCoordinates = component.getComponentBounds();
|
Collection<Coordinate> instanceCoordinates = component.getComponentBounds();
|
||||||
for (InstanceContext context : contexts) {
|
for (InstanceContext context : contexts) {
|
||||||
/*
|
|
||||||
* If the instance is not active in the current context, then
|
|
||||||
* skip the bound calculations. This is mildly confusing since
|
|
||||||
* getActiveInstances() implies that it will only return the
|
|
||||||
* instances that are active, but it returns all instances and
|
|
||||||
* the context indicates if it is active or not.
|
|
||||||
*/
|
|
||||||
if (!context.active) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
Collection<Coordinate> transformedCoords = new ArrayList<>(instanceCoordinates);
|
Collection<Coordinate> transformedCoords = new ArrayList<>(instanceCoordinates);
|
||||||
// mutating. Transforms coordinates in place.
|
// mutating. Transforms coordinates in place.
|
||||||
context.transform.transform(instanceCoordinates);
|
context.transform.transform(instanceCoordinates);
|
||||||
|
@ -296,7 +296,8 @@ public class FreeformFinSet extends FinSet {
|
|||||||
if (c.y > max)
|
if (c.y > max)
|
||||||
max = c.y;
|
max = c.y;
|
||||||
}
|
}
|
||||||
return max;
|
|
||||||
|
return max - Math.min(points.get(points.size() - 1).y, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -26,9 +26,8 @@ public class InstanceContext {
|
|||||||
return component.hashCode();
|
return component.hashCode();
|
||||||
}
|
}
|
||||||
|
|
||||||
public InstanceContext(final RocketComponent _component, final boolean _active, final int _instanceNumber, final Transformation _transform) {
|
public InstanceContext(final RocketComponent _component, final int _instanceNumber, final Transformation _transform) {
|
||||||
component = _component;
|
component = _component;
|
||||||
active = _active;
|
|
||||||
instanceNumber = _instanceNumber;
|
instanceNumber = _instanceNumber;
|
||||||
transform = _transform;
|
transform = _transform;
|
||||||
|
|
||||||
@ -48,7 +47,6 @@ public class InstanceContext {
|
|||||||
|
|
||||||
// ==== public ====
|
// ==== public ====
|
||||||
final public RocketComponent component;
|
final public RocketComponent component;
|
||||||
final public boolean active;
|
|
||||||
final public int instanceNumber;
|
final public int instanceNumber;
|
||||||
final public Transformation transform;
|
final public Transformation transform;
|
||||||
|
|
||||||
|
@ -34,7 +34,7 @@ public class InstanceMap extends HashMap<RocketComponent, ArrayList<InstanceCont
|
|||||||
put(key, new ArrayList<InstanceContext>());
|
put(key, new ArrayList<InstanceContext>());
|
||||||
}
|
}
|
||||||
|
|
||||||
final InstanceContext context = new InstanceContext(component, active, number, xform);
|
final InstanceContext context = new InstanceContext(component, number, xform);
|
||||||
get(key).add(context);
|
get(key).add(context);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -98,7 +98,7 @@ public class StageSeparationConfiguration implements FlightConfigurableParameter
|
|||||||
private static final Translator trans = Application.getTranslator();
|
private static final Translator trans = Application.getTranslator();
|
||||||
|
|
||||||
|
|
||||||
private SeparationEvent separationEvent = SeparationEvent.UPPER_IGNITION;
|
private SeparationEvent separationEvent = SeparationEvent.EJECTION;
|
||||||
private double separationDelay = 0;
|
private double separationDelay = 0;
|
||||||
|
|
||||||
private final List<StageSeparationConfiguration> configListeners = new LinkedList<>();
|
private final List<StageSeparationConfiguration> configListeners = new LinkedList<>();
|
||||||
|
@ -425,24 +425,28 @@ public class BasicEventSimulationEngine implements SimulationEngine {
|
|||||||
}
|
}
|
||||||
|
|
||||||
case STAGE_SEPARATION: {
|
case STAGE_SEPARATION: {
|
||||||
// Record the event.
|
|
||||||
currentStatus.getFlightData().addEvent(event);
|
|
||||||
|
|
||||||
RocketComponent boosterStage = event.getSource();
|
RocketComponent boosterStage = event.getSource();
|
||||||
final int stageNumber = boosterStage.getStageNumber();
|
final int stageNumber = boosterStage.getStageNumber();
|
||||||
|
|
||||||
// Mark the status as having dropped the booster
|
if (currentStatus.getConfiguration().isStageActive(stageNumber-1)) {
|
||||||
currentStatus.getConfiguration().clearStage( stageNumber);
|
// Record the event.
|
||||||
|
currentStatus.getFlightData().addEvent(event);
|
||||||
// Prepare the simulation branch
|
|
||||||
SimulationStatus boosterStatus = new SimulationStatus(currentStatus);
|
// Mark the status as having dropped the booster
|
||||||
boosterStatus.setFlightData(new FlightDataBranch(boosterStage.getName(), FlightDataType.TYPE_TIME));
|
currentStatus.getConfiguration().clearStage( stageNumber);
|
||||||
// Mark the booster status as only having the booster.
|
|
||||||
boosterStatus.getConfiguration().setOnlyStage(stageNumber);
|
// Prepare the simulation branch
|
||||||
toSimulate.push(boosterStatus);
|
SimulationStatus boosterStatus = new SimulationStatus(currentStatus);
|
||||||
log.info(String.format("==>> @ %g; from Branch: %s ---- Branching: %s ---- \n",
|
boosterStatus.setFlightData(new FlightDataBranch(boosterStage.getName(), FlightDataType.TYPE_TIME));
|
||||||
currentStatus.getSimulationTime(),
|
// Mark the booster status as only having the booster.
|
||||||
currentStatus.getFlightData().getBranchName(), boosterStatus.getFlightData().getBranchName()));
|
boosterStatus.getConfiguration().setOnlyStage(stageNumber);
|
||||||
|
toSimulate.push(boosterStatus);
|
||||||
|
log.info(String.format("==>> @ %g; from Branch: %s ---- Branching: %s ---- \n",
|
||||||
|
currentStatus.getSimulationTime(),
|
||||||
|
currentStatus.getFlightData().getBranchName(), boosterStatus.getFlightData().getBranchName()));
|
||||||
|
} else {
|
||||||
|
log.debug("upper stage is not active; not performing separation");
|
||||||
|
}
|
||||||
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -66,7 +66,6 @@ import net.sf.openrocket.simulation.listeners.SimulationListener;
|
|||||||
import net.sf.openrocket.startup.Application;
|
import net.sf.openrocket.startup.Application;
|
||||||
|
|
||||||
public class TestRockets {
|
public class TestRockets {
|
||||||
|
|
||||||
public final static FlightConfigurationId TEST_FCID_0 = new FlightConfigurationId("d010716e-ce0e-469d-ae46-190f3653ebbf");
|
public final static FlightConfigurationId TEST_FCID_0 = new FlightConfigurationId("d010716e-ce0e-469d-ae46-190f3653ebbf");
|
||||||
public final static FlightConfigurationId TEST_FCID_1 = new FlightConfigurationId("f41bee5b-ebb8-4d92-bce7-53001577a313");
|
public final static FlightConfigurationId TEST_FCID_1 = new FlightConfigurationId("f41bee5b-ebb8-4d92-bce7-53001577a313");
|
||||||
public final static FlightConfigurationId TEST_FCID_2 = new FlightConfigurationId("3e8d1280-53c2-4234-89a7-de215ef5cd69");
|
public final static FlightConfigurationId TEST_FCID_2 = new FlightConfigurationId("3e8d1280-53c2-4234-89a7-de215ef5cd69");
|
||||||
@ -1705,30 +1704,32 @@ public class TestRockets {
|
|||||||
|
|
||||||
// find the body and fins
|
// find the body and fins
|
||||||
final InstanceMap imap = rocket.getSelectedConfiguration().getActiveInstances();
|
final InstanceMap imap = rocket.getSelectedConfiguration().getActiveInstances();
|
||||||
for(Map.Entry<RocketComponent, ArrayList<InstanceContext>> entry: imap.entrySet() ) {
|
RocketComponent c = null;
|
||||||
RocketComponent c = entry.getKey();
|
for(Map.Entry<RocketComponent, ArrayList<InstanceContext>> entry: imap.entrySet() ) {
|
||||||
|
c = entry.getKey();
|
||||||
if (c instanceof TrapezoidFinSet) {
|
if (c instanceof TrapezoidFinSet) {
|
||||||
final TrapezoidFinSet fins = (TrapezoidFinSet) c;
|
break;
|
||||||
final BodyTube body = (BodyTube) fins.getParent();
|
|
||||||
body.removeChild(fins);
|
|
||||||
|
|
||||||
// create a PodSet to hook the fins to
|
|
||||||
PodSet podset = new PodSet();
|
|
||||||
podset.setInstanceCount(fins.getFinCount());
|
|
||||||
|
|
||||||
body.addChild(podset);
|
|
||||||
|
|
||||||
// put a phantom body tube on the pods
|
|
||||||
BodyTube podBody = new BodyTube(fins.getRootChord(), 0);
|
|
||||||
podBody.setName("Pod Body");
|
|
||||||
podset.addChild(podBody);
|
|
||||||
|
|
||||||
// change the number of fins to 1 and put the revised
|
|
||||||
// finset on the podbody
|
|
||||||
fins.setFinCount(1);
|
|
||||||
podBody.addChild(fins);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
final TrapezoidFinSet fins = (TrapezoidFinSet) c;
|
||||||
|
final BodyTube body = (BodyTube) fins.getParent();
|
||||||
|
body.removeChild(fins);
|
||||||
|
|
||||||
|
// create a PodSet to hook the fins to
|
||||||
|
PodSet podset = new PodSet();
|
||||||
|
podset.setInstanceCount(fins.getFinCount());
|
||||||
|
|
||||||
|
body.addChild(podset);
|
||||||
|
|
||||||
|
// put a phantom body tube on the pods
|
||||||
|
BodyTube podBody = new BodyTube(fins.getRootChord(), 0);
|
||||||
|
podBody.setName("Pod Body");
|
||||||
|
podset.addChild(podBody);
|
||||||
|
|
||||||
|
// change the number of fins to 1 and put the revised
|
||||||
|
// finset on the podbody
|
||||||
|
fins.setFinCount(1);
|
||||||
|
podBody.addChild(fins);
|
||||||
|
|
||||||
return rocket;
|
return rocket;
|
||||||
}
|
}
|
||||||
|
@ -1 +1 @@
|
|||||||
Subproject commit 52e1e2c0800ebf62fd0e9cecd69aaaed6cddf80e
|
Subproject commit 8304c0fd3dc80d65c40af4da83268ec1b32931d6
|
@ -0,0 +1,64 @@
|
|||||||
|
package net.sf.openrocket.gui.adaptors;
|
||||||
|
|
||||||
|
import net.sf.openrocket.rocketcomponent.ComponentChangeEvent;
|
||||||
|
import net.sf.openrocket.rocketcomponent.ComponentChangeListener;
|
||||||
|
import net.sf.openrocket.rocketcomponent.RocketComponent;
|
||||||
|
import net.sf.openrocket.rocketcomponent.Transition;
|
||||||
|
|
||||||
|
import javax.swing.AbstractListModel;
|
||||||
|
import javax.swing.ComboBoxModel;
|
||||||
|
|
||||||
|
public class TransitionShapeModel extends AbstractListModel<Transition.Shape>
|
||||||
|
implements ComboBoxModel<Transition.Shape>, ComponentChangeListener {
|
||||||
|
private final RocketComponent component;
|
||||||
|
private final Transition.Shape[] typeList = Transition.Shape.values();
|
||||||
|
private Transition.Shape previousType;
|
||||||
|
|
||||||
|
public TransitionShapeModel(RocketComponent component) {
|
||||||
|
this.component = component;
|
||||||
|
if (component instanceof Transition) {
|
||||||
|
previousType = ((Transition) component).getType();
|
||||||
|
setSelectedItem(previousType);
|
||||||
|
component.addComponentChangeListener(this);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setSelectedItem(Object item) {
|
||||||
|
if (!(component instanceof Transition) || !(item instanceof Transition.Shape)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
((Transition) component).setType((Transition.Shape) item);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Object getSelectedItem() {
|
||||||
|
if (component instanceof Transition) {
|
||||||
|
return ((Transition) component).getType();
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getSize() {
|
||||||
|
return typeList.length;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Transition.Shape getElementAt(int index) {
|
||||||
|
return typeList[index];
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void componentChanged(ComponentChangeEvent e) {
|
||||||
|
if (!(component instanceof Transition)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (previousType != ((Transition) component).getType()) {
|
||||||
|
previousType = ((Transition) component).getType();
|
||||||
|
fireContentsChanged(this, 0, 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -16,6 +16,7 @@ import net.sf.openrocket.document.OpenRocketDocument;
|
|||||||
import net.sf.openrocket.gui.SpinnerEditor;
|
import net.sf.openrocket.gui.SpinnerEditor;
|
||||||
import net.sf.openrocket.gui.adaptors.BooleanModel;
|
import net.sf.openrocket.gui.adaptors.BooleanModel;
|
||||||
import net.sf.openrocket.gui.adaptors.DoubleModel;
|
import net.sf.openrocket.gui.adaptors.DoubleModel;
|
||||||
|
import net.sf.openrocket.gui.adaptors.TransitionShapeModel;
|
||||||
import net.sf.openrocket.gui.components.BasicSlider;
|
import net.sf.openrocket.gui.components.BasicSlider;
|
||||||
import net.sf.openrocket.gui.components.DescriptionArea;
|
import net.sf.openrocket.gui.components.DescriptionArea;
|
||||||
import net.sf.openrocket.gui.components.UnitSelector;
|
import net.sf.openrocket.gui.components.UnitSelector;
|
||||||
@ -52,18 +53,15 @@ public class NoseConeConfig extends RocketComponentConfig {
|
|||||||
{//// Nose cone shape:
|
{//// Nose cone shape:
|
||||||
panel.add(new JLabel(trans.get("NoseConeCfg.lbl.Noseconeshape")));
|
panel.add(new JLabel(trans.get("NoseConeCfg.lbl.Noseconeshape")));
|
||||||
|
|
||||||
Transition.Shape selected = ((NoseCone) component).getType();
|
final JComboBox<Transition.Shape> typeBox = new JComboBox<>(new TransitionShapeModel(c));
|
||||||
Transition.Shape[] typeList = Transition.Shape.values();
|
|
||||||
|
|
||||||
final JComboBox<Transition.Shape> typeBox = new JComboBox<Transition.Shape>(typeList);
|
|
||||||
typeBox.setEditable(false);
|
typeBox.setEditable(false);
|
||||||
typeBox.setSelectedItem(selected);
|
|
||||||
typeBox.addActionListener(new ActionListener() {
|
typeBox.addActionListener(new ActionListener() {
|
||||||
@Override
|
@Override
|
||||||
public void actionPerformed(ActionEvent e) {
|
public void actionPerformed(ActionEvent e) {
|
||||||
Transition.Shape s = (Transition.Shape) typeBox.getSelectedItem();
|
Transition.Shape s = (Transition.Shape) typeBox.getSelectedItem();
|
||||||
((NoseCone) component).setType(s);
|
if (s != null) {
|
||||||
description.setText(PREDESC + s.getNoseConeDescription());
|
description.setText(PREDESC + s.getNoseConeDescription());
|
||||||
|
}
|
||||||
updateEnabled();
|
updateEnabled();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
@ -15,6 +15,7 @@ import net.sf.openrocket.document.OpenRocketDocument;
|
|||||||
import net.sf.openrocket.gui.SpinnerEditor;
|
import net.sf.openrocket.gui.SpinnerEditor;
|
||||||
import net.sf.openrocket.gui.adaptors.BooleanModel;
|
import net.sf.openrocket.gui.adaptors.BooleanModel;
|
||||||
import net.sf.openrocket.gui.adaptors.DoubleModel;
|
import net.sf.openrocket.gui.adaptors.DoubleModel;
|
||||||
|
import net.sf.openrocket.gui.adaptors.TransitionShapeModel;
|
||||||
import net.sf.openrocket.gui.components.BasicSlider;
|
import net.sf.openrocket.gui.components.BasicSlider;
|
||||||
import net.sf.openrocket.gui.components.DescriptionArea;
|
import net.sf.openrocket.gui.components.DescriptionArea;
|
||||||
import net.sf.openrocket.gui.components.UnitSelector;
|
import net.sf.openrocket.gui.components.UnitSelector;
|
||||||
@ -54,18 +55,15 @@ public class TransitionConfig extends RocketComponentConfig {
|
|||||||
//// Transition shape:
|
//// Transition shape:
|
||||||
panel.add(new JLabel(trans.get("TransitionCfg.lbl.Transitionshape")));
|
panel.add(new JLabel(trans.get("TransitionCfg.lbl.Transitionshape")));
|
||||||
|
|
||||||
Transition.Shape selected = ((Transition) component).getType();
|
typeBox = new JComboBox<>(new TransitionShapeModel(c));
|
||||||
Transition.Shape[] typeList = Transition.Shape.values();
|
|
||||||
|
|
||||||
typeBox = new JComboBox<Transition.Shape>(typeList);
|
|
||||||
typeBox.setEditable(false);
|
typeBox.setEditable(false);
|
||||||
typeBox.setSelectedItem(selected);
|
|
||||||
typeBox.addActionListener(new ActionListener() {
|
typeBox.addActionListener(new ActionListener() {
|
||||||
@Override
|
@Override
|
||||||
public void actionPerformed(ActionEvent e) {
|
public void actionPerformed(ActionEvent e) {
|
||||||
Transition.Shape s = (Transition.Shape) typeBox.getSelectedItem();
|
Transition.Shape s = (Transition.Shape) typeBox.getSelectedItem();
|
||||||
((Transition) component).setType(s);
|
if (s != null) {
|
||||||
description.setText(PREDESC + s.getTransitionDescription());
|
description.setText(PREDESC + s.getTransitionDescription());
|
||||||
|
}
|
||||||
updateEnabled();
|
updateEnabled();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
@ -85,21 +85,19 @@ public abstract class RocketRenderer {
|
|||||||
if (ignore != null && ignore.contains(comp))
|
if (ignore != null && ignore.contains(comp))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
if( geom.active ) {
|
final int hashCode = comp.hashCode();
|
||||||
final int hashCode = comp.hashCode();
|
|
||||||
|
selectionMap.put(hashCode, comp);
|
||||||
selectionMap.put(hashCode, comp);
|
|
||||||
|
gl.glColor4ub((byte) ((hashCode >> 24) & 0xFF), // red channel (LSB)
|
||||||
gl.glColor4ub((byte) ((hashCode >> 24) & 0xFF), // red channel (LSB)
|
(byte) ((hashCode >> 16) & 0xFF), // green channel
|
||||||
(byte) ((hashCode >> 16) & 0xFF), // green channel
|
(byte) ((hashCode >> 8) & 0xFF), // blue channel
|
||||||
(byte) ((hashCode >> 8) & 0xFF), // blue channel
|
(byte) ((hashCode) & 0xFF)); // alpha channel (MSB)
|
||||||
(byte) ((hashCode) & 0xFF)); // alpha channel (MSB)
|
|
||||||
|
if (isDrawnTransparent(comp)) {
|
||||||
if (isDrawnTransparent(comp)) {
|
geom.render(gl, Surface.INSIDE);
|
||||||
geom.render(gl, Surface.INSIDE);
|
} else {
|
||||||
} else {
|
geom.render(gl, Surface.ALL);
|
||||||
geom.render(gl, Surface.ALL);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -186,7 +184,6 @@ public abstract class RocketRenderer {
|
|||||||
|
|
||||||
for(InstanceContext context: contextList ) {
|
for(InstanceContext context: contextList ) {
|
||||||
Geometry instanceGeometry = cr.getComponentGeometry( comp, context.transform );
|
Geometry instanceGeometry = cr.getComponentGeometry( comp, context.transform );
|
||||||
instanceGeometry.active = context.active;
|
|
||||||
treeGeometry.add( instanceGeometry );
|
treeGeometry.add( instanceGeometry );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -196,19 +193,15 @@ public abstract class RocketRenderer {
|
|||||||
private void renderTree( GL2 gl, final Collection<Geometry> geometryList){
|
private void renderTree( GL2 gl, final Collection<Geometry> geometryList){
|
||||||
//cycle through opaque components first, then transparent to preserve proper depth testing
|
//cycle through opaque components first, then transparent to preserve proper depth testing
|
||||||
for(Geometry geom: geometryList ) {
|
for(Geometry geom: geometryList ) {
|
||||||
if( geom.active ) {
|
//if not transparent
|
||||||
//if not transparent
|
if( !isDrawnTransparent( (RocketComponent)geom.obj) ){
|
||||||
if( !isDrawnTransparent( (RocketComponent)geom.obj) ){
|
renderComponent(gl, geom, 1.0f);
|
||||||
renderComponent(gl, geom, 1.0f);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
for(Geometry geom: geometryList ) {
|
for(Geometry geom: geometryList ) {
|
||||||
if( geom.active ) {
|
if( isDrawnTransparent( (RocketComponent)geom.obj) ){
|
||||||
if( isDrawnTransparent( (RocketComponent)geom.obj) ){
|
// Draw T&T front faces blended, without depth test
|
||||||
// Draw T&T front faces blended, without depth test
|
renderComponent(gl, geom, 0.2f);
|
||||||
renderComponent(gl, geom, 0.2f);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -25,8 +25,6 @@ public abstract class Geometry {
|
|||||||
public final Object obj;
|
public final Object obj;
|
||||||
public final Transformation transform;
|
public final Transformation transform;
|
||||||
|
|
||||||
public boolean active;
|
|
||||||
|
|
||||||
public abstract void render(GL2 gl, Surface which );
|
public abstract void render(GL2 gl, Surface which );
|
||||||
|
|
||||||
private Geometry() {
|
private Geometry() {
|
||||||
|
@ -3,29 +3,37 @@ package net.sf.openrocket.gui.plot;
|
|||||||
import java.awt.Window;
|
import java.awt.Window;
|
||||||
import java.awt.event.ActionEvent;
|
import java.awt.event.ActionEvent;
|
||||||
import java.awt.event.ActionListener;
|
import java.awt.event.ActionListener;
|
||||||
|
import java.awt.event.ComponentAdapter;
|
||||||
|
import java.awt.event.ComponentEvent;
|
||||||
import java.awt.event.InputEvent;
|
import java.awt.event.InputEvent;
|
||||||
import java.awt.event.ItemEvent;
|
import java.awt.event.ItemEvent;
|
||||||
import java.awt.event.ItemListener;
|
import java.awt.event.ItemListener;
|
||||||
|
import java.io.File;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
|
|
||||||
import javax.swing.JButton;
|
import javax.swing.JButton;
|
||||||
import javax.swing.JCheckBox;
|
import javax.swing.JCheckBox;
|
||||||
import javax.swing.JComboBox;
|
import javax.swing.JComboBox;
|
||||||
import javax.swing.JDialog;
|
import javax.swing.JDialog;
|
||||||
|
import javax.swing.JFileChooser;
|
||||||
import javax.swing.JLabel;
|
import javax.swing.JLabel;
|
||||||
import javax.swing.JPanel;
|
import javax.swing.JPanel;
|
||||||
|
|
||||||
import net.miginfocom.swing.MigLayout;
|
import net.miginfocom.swing.MigLayout;
|
||||||
import net.sf.openrocket.document.Simulation;
|
import net.sf.openrocket.document.Simulation;
|
||||||
import net.sf.openrocket.gui.components.StyledLabel;
|
import net.sf.openrocket.gui.components.StyledLabel;
|
||||||
|
import net.sf.openrocket.gui.util.FileHelper;
|
||||||
import net.sf.openrocket.gui.util.GUIUtil;
|
import net.sf.openrocket.gui.util.GUIUtil;
|
||||||
import net.sf.openrocket.gui.util.Icons;
|
import net.sf.openrocket.gui.util.Icons;
|
||||||
|
import net.sf.openrocket.gui.util.SwingPreferences;
|
||||||
import net.sf.openrocket.l10n.Translator;
|
import net.sf.openrocket.l10n.Translator;
|
||||||
import net.sf.openrocket.startup.Application;
|
import net.sf.openrocket.startup.Application;
|
||||||
import net.sf.openrocket.startup.Preferences;
|
import net.sf.openrocket.startup.Preferences;
|
||||||
import net.sf.openrocket.gui.widgets.SelectColorButton;
|
import net.sf.openrocket.gui.widgets.SelectColorButton;
|
||||||
|
|
||||||
import org.jfree.chart.ChartPanel;
|
import org.jfree.chart.ChartPanel;
|
||||||
|
import org.jfree.chart.ChartUtilities;
|
||||||
|
import org.jfree.chart.JFreeChart;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Dialog that shows a plot of a simulation results based on user options.
|
* Dialog that shows a plot of a simulation results based on user options.
|
||||||
@ -50,7 +58,14 @@ public class SimulationPlotDialog extends JDialog {
|
|||||||
this.add(panel);
|
this.add(panel);
|
||||||
|
|
||||||
final ChartPanel chartPanel = new SimulationChart(myPlot.getJFreeChart());
|
final ChartPanel chartPanel = new SimulationChart(myPlot.getJFreeChart());
|
||||||
|
final JFreeChart jChart = myPlot.getJFreeChart();
|
||||||
panel.add(chartPanel, "grow, wrap 20lp");
|
panel.add(chartPanel, "grow, wrap 20lp");
|
||||||
|
|
||||||
|
// Ensures normal aspect-ratio of chart elements when resizing the panel
|
||||||
|
chartPanel.setMinimumDrawWidth(0);
|
||||||
|
chartPanel.setMaximumDrawWidth(Integer.MAX_VALUE);
|
||||||
|
chartPanel.setMinimumDrawHeight(0);
|
||||||
|
chartPanel.setMaximumDrawHeight(Integer.MAX_VALUE);
|
||||||
|
|
||||||
//// Description text
|
//// Description text
|
||||||
JLabel label = new StyledLabel(trans.get("PlotDialog.lbl.Chart"), -2);
|
JLabel label = new StyledLabel(trans.get("PlotDialog.lbl.Chart"), -2);
|
||||||
@ -108,6 +123,16 @@ public class SimulationPlotDialog extends JDialog {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
panel.add(button, "gapleft rel");
|
panel.add(button, "gapleft rel");
|
||||||
|
|
||||||
|
//// Print chart button
|
||||||
|
button = new SelectColorButton(trans.get("PlotDialog.btn.exportImage"));
|
||||||
|
button.addActionListener(new ActionListener() {
|
||||||
|
@Override
|
||||||
|
public void actionPerformed(ActionEvent e) {
|
||||||
|
doPngExport(chartPanel,jChart);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
panel.add(button, "gapleft rel");
|
||||||
|
|
||||||
//// Add series selection box
|
//// Add series selection box
|
||||||
ArrayList<String> stages = new ArrayList<String>();
|
ArrayList<String> stages = new ArrayList<String>();
|
||||||
@ -141,16 +166,43 @@ public class SimulationPlotDialog extends JDialog {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
panel.add(button, "right");
|
panel.add(button, "right");
|
||||||
|
|
||||||
this.setLocationByPlatform(true);
|
this.setLocationByPlatform(true);
|
||||||
this.pack();
|
this.pack();
|
||||||
|
|
||||||
GUIUtil.setDisposableDialogOptions(this, button);
|
GUIUtil.setDisposableDialogOptions(this, button);
|
||||||
GUIUtil.rememberWindowSize(this);
|
GUIUtil.rememberWindowSize(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private boolean doPngExport(ChartPanel chartPanel, JFreeChart chart){
|
||||||
|
JFileChooser chooser = new JFileChooser();
|
||||||
|
chooser.setAcceptAllFileFilterUsed(false);
|
||||||
|
chooser.setFileFilter(FileHelper.PNG_FILTER);
|
||||||
|
chooser.setCurrentDirectory(((SwingPreferences) Application.getPreferences()).getDefaultDirectory());
|
||||||
|
|
||||||
|
//// Ensures No Problems When Choosing File
|
||||||
|
if (chooser.showSaveDialog(this) != JFileChooser.APPROVE_OPTION)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
File file = chooser.getSelectedFile();
|
||||||
|
if (file == null)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
file = FileHelper.forceExtension(file, "png");
|
||||||
|
if (!FileHelper.confirmWrite(file, this)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
//// Uses JFreeChart Built In PNG Export Method
|
||||||
|
try{
|
||||||
|
ChartUtilities.saveChartAsPNG(file, chart, chartPanel.getWidth(), chartPanel.getHeight());
|
||||||
|
} catch(Exception e){
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Static method that shows a plot with the specified parameters.
|
* Static method that shows a plot with the specified parameters.
|
||||||
*
|
*
|
||||||
|
@ -378,11 +378,7 @@ public class RocketFigure extends AbstractScaleFigure {
|
|||||||
|
|
||||||
for(InstanceContext context: contextList ) {
|
for(InstanceContext context: contextList ) {
|
||||||
final Transformation currentTransform = this.axialRotation.applyTransformation(context.transform);
|
final Transformation currentTransform = this.axialRotation.applyTransformation(context.transform);
|
||||||
|
allShapes = addThisShape( allShapes, this.currentViewType, comp, currentTransform);
|
||||||
// generate shape for this component, if active
|
|
||||||
if( context.active ) {
|
|
||||||
allShapes = addThisShape( allShapes, this.currentViewType, comp, currentTransform);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -56,6 +56,10 @@ public final class FileHelper {
|
|||||||
public static final FileFilter CSV_FILTER =
|
public static final FileFilter CSV_FILTER =
|
||||||
new SimpleFileFilter(trans.get("FileHelper.CSV_FILTER"), ".csv");
|
new SimpleFileFilter(trans.get("FileHelper.CSV_FILTER"), ".csv");
|
||||||
|
|
||||||
|
/** File filter for PNG files (*.png) */
|
||||||
|
public static final FileFilter PNG_FILTER =
|
||||||
|
new SimpleFileFilter(trans.get("FileHelper.PNG_FILTER"), ".png");
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user