Merge branch 'openrocket:unstable' into fix-2024
This commit is contained in:
commit
1fa82c3fef
@ -228,6 +228,10 @@ edtmotorconfdlg.tbl.Separationheader = Separation
|
||||
RenameConfigDialog.title = Rename Configuration
|
||||
RenameConfigDialog.lbl.name = Name for flight configuration:
|
||||
RenameConfigDialog.but.reset = Reset to default
|
||||
RenameConfigDialog.lbl.infoMotors = The text '<b>{motors}</b>' will be replaced with the <b>motor designation(s).</b><br><pre>\te.g. '{motors} \u2192 'M1350-0'</pre>
|
||||
RenameConfigDialog.lbl.infoManufacturers = The text '<b>{manufacturers}</b>' will be replaced with the <b>motor manufacturer(s).</b><br><pre>\te.g. '{manufacturers}' \u2192 'AeroTech'</pre>
|
||||
RenameConfigDialog.lbl.infoCombination = A <b>combination</b> of the above can be used.<br><pre>\te.g. '{manufacturers motors}' \u2192 'AeroTech M1350-0'</pre>
|
||||
|
||||
|
||||
! Example design dialog
|
||||
exdesigndlg.but.open = Open
|
||||
@ -551,6 +555,7 @@ simpanel.col.Timetoapogee = Time to apogee
|
||||
simpanel.col.Flighttime = Flight time
|
||||
simpanel.col.Groundhitvelocity = Ground hit velocity
|
||||
simpanel.ttip.uptodate = <i>Up to date</i>
|
||||
simpanel.ttip.loaded = <i>Loaded from file</i>
|
||||
simpanel.ttip.outdated = <i><font color=\"red\">Out of date</font></i><br>Click <i><b>Run simulations</b></i> to simulate.
|
||||
simpanel.ttip.external = <i>Imported data</i>
|
||||
simpanel.ttip.notSimulated = <i>Not simulated yet</i><br>Click <i><b>Run simulations</b></i> to simulate.
|
||||
@ -2261,6 +2266,7 @@ SeparationSelectionDialog.opt.override = Override for the {0} flight configurati
|
||||
MotorConfigurationPanel.description = <b>Select the motors and motor ignition events of the selected flight configuration.</b><br> <em>Motor mounts:</em> Select which components function as motor mounts.<br> <em>Motor configurations:</em> Select the motor and ignition event for each motor mount.
|
||||
|
||||
MotorDescriptionSubstitutor.description = Motors in the configuration
|
||||
MotorManufacturerSubstitutor.description = Motor manufacturers in the configuration
|
||||
|
||||
|
||||
!Photo Panel
|
||||
|
@ -380,6 +380,20 @@ public class BarrowmanCalculator extends AbstractAerodynamicCalculator {
|
||||
}
|
||||
|
||||
}
|
||||
} else {
|
||||
/*
|
||||
It could be that the component is a child of a PodSet or ParallelStage, and it is flush with
|
||||
the previous component. In this case, the component is overlapping.
|
||||
*/
|
||||
RocketComponent prevCompParent = prevComp.getParent();
|
||||
RocketComponent compParent = comp.getParent();
|
||||
int prevCompPos = prevCompParent.getChildPosition(prevComp);
|
||||
RocketComponent nextComp = prevCompPos + 1 >= prevCompParent.getChildCount() ?
|
||||
null : prevCompParent.getChild(prevCompPos + 1);
|
||||
if ((compParent instanceof PodSet || compParent instanceof ParallelStage) &&
|
||||
MathUtil.equals(symXfore, prevXaft) && (compParent.getParent() == nextComp)) {
|
||||
warnings.add(Warning.PODSET_OVERLAP, comp.getParent().toString());
|
||||
}
|
||||
}
|
||||
}
|
||||
prevComp = sym;
|
||||
|
@ -146,40 +146,22 @@ public class Simulation implements ChangeSource, Cloneable {
|
||||
if (options == null)
|
||||
throw new IllegalArgumentException("options cannot be null");
|
||||
|
||||
this.document = document;
|
||||
this.rocket = rocket;
|
||||
|
||||
if (status == Status.UPTODATE) {
|
||||
this.status = Status.LOADED;
|
||||
} else if (data == null) {
|
||||
this.status = Status.NOT_SIMULATED;
|
||||
} else {
|
||||
this.status = status;
|
||||
}
|
||||
|
||||
this.name = name;
|
||||
|
||||
this.status = status;
|
||||
this.simulatedConditions = options.clone();
|
||||
this.simulatedData = data;
|
||||
this.document = document;
|
||||
addChangeListener(this.document);
|
||||
|
||||
this.options = options;
|
||||
|
||||
this.options.addChangeListener(new ConditionListener());
|
||||
|
||||
final FlightConfiguration config = rocket.getSelectedConfiguration();
|
||||
this.setFlightConfigurationId(config.getFlightConfigurationID());
|
||||
|
||||
options.addChangeListener(new ConditionListener());
|
||||
addChangeListener(document);
|
||||
|
||||
if (extensions != null) {
|
||||
this.simulationExtensions.addAll(extensions);
|
||||
}
|
||||
|
||||
|
||||
if (data != null && this.status != Status.NOT_SIMULATED) {
|
||||
simulatedData = data;
|
||||
if (this.status == Status.LOADED) {
|
||||
simulatedConditions = options.clone();
|
||||
simulatedConfigurationID = config.getModID();
|
||||
}
|
||||
}
|
||||
|
||||
this.simulatedConfigurationID = config.getModID();
|
||||
|
||||
this.simulationExtensions.addAll(extensions);
|
||||
}
|
||||
|
||||
public FlightConfiguration getActiveConfiguration() {
|
||||
|
@ -92,12 +92,6 @@ class FlightDataHandler extends AbstractElementHandler {
|
||||
public void endHandler(String element, HashMap<String, String> attributes,
|
||||
String content, WarningSet warnings) {
|
||||
|
||||
// If no <databranch> tag in XML, then there is no sim data
|
||||
if (dataHandler == null) {
|
||||
data = null;
|
||||
return;
|
||||
}
|
||||
|
||||
if (branches.size() > 0) {
|
||||
data = new FlightData(branches.toArray(new FlightDataBranch[0]));
|
||||
} else {
|
||||
@ -158,4 +152,4 @@ class FlightDataHandler extends AbstractElementHandler {
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
|
@ -109,13 +109,6 @@ class SingleSimulationHandler extends AbstractElementHandler {
|
||||
public void endHandler(String element, HashMap<String, String> attributes,
|
||||
String content, WarningSet warnings) {
|
||||
|
||||
String s = attributes.get("status");
|
||||
Simulation.Status status = (Status) DocumentConfig.findEnum(s, Simulation.Status.class);
|
||||
if (status == null) {
|
||||
warnings.add("Simulation status unknown, assuming outdated.");
|
||||
status = Simulation.Status.OUTDATED;
|
||||
}
|
||||
|
||||
SimulationOptions options;
|
||||
FlightConfigurationId idToSet= FlightConfigurationId.ERROR_FCID;
|
||||
if (conditionHandler != null) {
|
||||
@ -126,16 +119,23 @@ class SingleSimulationHandler extends AbstractElementHandler {
|
||||
options = new SimulationOptions();
|
||||
}
|
||||
|
||||
if (name == null)
|
||||
if (name == null)
|
||||
name = "Simulation";
|
||||
|
||||
// If the simulation was saved with flight data (which may just be a summary)
|
||||
// mark it as loaded from the file else as not simulated. We're ignoring the
|
||||
// simulation status attribute, since (1) it really isn't relevant now, and (2)
|
||||
// sim summaries are getting marked as not simulated when they're saved
|
||||
FlightData data;
|
||||
if (dataHandler == null)
|
||||
data = null;
|
||||
else
|
||||
data = dataHandler.getFlightData();
|
||||
|
||||
if (data == null) {
|
||||
Simulation.Status status;
|
||||
if (data != null) {
|
||||
status = Status.LOADED;
|
||||
} else {
|
||||
status = Status.NOT_SIMULATED;
|
||||
}
|
||||
|
||||
@ -153,4 +153,4 @@ class SingleSimulationHandler extends AbstractElementHandler {
|
||||
return extension;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,250 @@
|
||||
package net.sf.openrocket.formatting;
|
||||
|
||||
import com.google.inject.Inject;
|
||||
import net.sf.openrocket.l10n.Translator;
|
||||
import net.sf.openrocket.motor.Motor;
|
||||
import net.sf.openrocket.motor.MotorConfiguration;
|
||||
import net.sf.openrocket.motor.ThrustCurveMotor;
|
||||
import net.sf.openrocket.plugin.Plugin;
|
||||
import net.sf.openrocket.rocketcomponent.AxialStage;
|
||||
import net.sf.openrocket.rocketcomponent.FlightConfiguration;
|
||||
import net.sf.openrocket.rocketcomponent.FlightConfigurationId;
|
||||
import net.sf.openrocket.rocketcomponent.MotorMount;
|
||||
import net.sf.openrocket.rocketcomponent.Rocket;
|
||||
import net.sf.openrocket.rocketcomponent.RocketComponent;
|
||||
import net.sf.openrocket.util.ArrayList;
|
||||
import net.sf.openrocket.util.Chars;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
/**
|
||||
* General substitutor for motor configurations. This currently includes substitutions for
|
||||
* - {motors} - the motor designation (e.g. "M1350-0")
|
||||
* - {manufacturers} - the motor manufacturer (e.g. "AeroTech")
|
||||
* - a combination of motors and manufacturers, e.g. {motors | manufacturers} -> "M1350-0 | AeroTech"
|
||||
* You can choose which comes first and what the separator is. E.g. {manufacturers, motors} -> "AeroTech, M1350-0".
|
||||
*
|
||||
* <p>
|
||||
* This substitutor is added through injection. All substitutors with the "@Plugin" tag in the formatting package will
|
||||
* be included automatically.
|
||||
*/
|
||||
@Plugin
|
||||
public class MotorConfigurationSubstitutor implements RocketSubstitutor {
|
||||
public static final String SUBSTITUTION_START = "{";
|
||||
public static final String SUBSTITUTION_END = "}";
|
||||
public static final String SUBSTITUTION_MOTORS = "motors";
|
||||
public static final String SUBSTITUTION_MANUFACTURERS = "manufacturers";
|
||||
|
||||
// Substitutions for combinations of motors and manufacturers
|
||||
private static final String SUBSTITUTION_PATTERN = "\\" + SUBSTITUTION_START +
|
||||
"(" + SUBSTITUTION_MOTORS + "|" + SUBSTITUTION_MANUFACTURERS + ")" +
|
||||
"(.*?)" +
|
||||
"(" + SUBSTITUTION_MOTORS + "|" + SUBSTITUTION_MANUFACTURERS + ")" +
|
||||
"\\" + SUBSTITUTION_END;
|
||||
|
||||
@Inject
|
||||
private Translator trans;
|
||||
|
||||
@Override
|
||||
public boolean containsSubstitution(String input) {
|
||||
return getSubstitutionContent(input) != null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String substitute(String input, Rocket rocket, FlightConfigurationId configId) {
|
||||
String description = getConfigurationSubstitution(input, rocket, configId);
|
||||
String substitutionString = getSubstiutionString(input);
|
||||
if (substitutionString != null) {
|
||||
return input.replace(substitutionString, description);
|
||||
}
|
||||
return input;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<String, String> getDescriptions() {
|
||||
return null;
|
||||
}
|
||||
|
||||
public String getConfigurationSubstitution(String input, Rocket rocket, FlightConfigurationId fcid) {
|
||||
StringBuilder configurations = new StringBuilder();
|
||||
int motorCount = 0;
|
||||
|
||||
// Iterate over each stage and store the manufacturer of each motor
|
||||
List<List<String>> list = new ArrayList<>();
|
||||
List<String> currentList = new ArrayList<>();
|
||||
|
||||
String[] content = getSubstitutionContent(input);
|
||||
if (content == null) {
|
||||
return "";
|
||||
}
|
||||
|
||||
FlightConfiguration config = rocket.getFlightConfiguration(fcid);
|
||||
for (RocketComponent c : rocket) {
|
||||
if (c instanceof AxialStage) {
|
||||
currentList = new ArrayList<>();
|
||||
list.add(currentList);
|
||||
} else if (c instanceof MotorMount) {
|
||||
MotorMount mount = (MotorMount) c;
|
||||
MotorConfiguration inst = mount.getMotorConfig(fcid);
|
||||
Motor motor = inst.getMotor();
|
||||
|
||||
if (mount.isMotorMount() && config.isComponentActive(mount) && (motor != null)) {
|
||||
String motorDesignation = motor.getDesignation(inst.getEjectionDelay());
|
||||
String manufacturer = "";
|
||||
if (motor instanceof ThrustCurveMotor) {
|
||||
manufacturer = ((ThrustCurveMotor) motor).getManufacturer().getDisplayName();
|
||||
}
|
||||
|
||||
for (int i = 0; i < mount.getMotorCount(); i++) {
|
||||
if (content.length == 2) {
|
||||
if (SUBSTITUTION_MOTORS.equals(content[1])) {
|
||||
currentList.add(motorDesignation);
|
||||
} else if (SUBSTITUTION_MANUFACTURERS.equals(content[1])) {
|
||||
currentList.add(manufacturer);
|
||||
} else {
|
||||
continue;
|
||||
}
|
||||
} else if (content.length == 4) {
|
||||
String configString;
|
||||
if (content[1].equals(SUBSTITUTION_MOTORS)) {
|
||||
configString = motorDesignation;
|
||||
} else if (content[1].equals(SUBSTITUTION_MANUFACTURERS)) {
|
||||
configString = manufacturer;
|
||||
} else {
|
||||
continue;
|
||||
}
|
||||
configString += content[2];
|
||||
if (content[3].equals(SUBSTITUTION_MOTORS)) {
|
||||
configString += motorDesignation;
|
||||
} else if (content[3].equals(SUBSTITUTION_MANUFACTURERS)) {
|
||||
configString += manufacturer;
|
||||
} else {
|
||||
continue;
|
||||
}
|
||||
currentList.add(configString);
|
||||
} else {
|
||||
continue;
|
||||
}
|
||||
motorCount++;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (motorCount == 0) {
|
||||
return trans.get("Rocket.motorCount.Nomotor");
|
||||
}
|
||||
|
||||
// Change multiple occurrences of a motor to n x motor
|
||||
List<String> stages = new ArrayList<>();
|
||||
for (List<String> stage : list) {
|
||||
String stageName = "";
|
||||
String previous = null;
|
||||
int count = 0;
|
||||
|
||||
Collections.sort(stage);
|
||||
for (String current : stage) {
|
||||
if (current.equals(previous)) {
|
||||
count++;
|
||||
} else {
|
||||
if (previous != null) {
|
||||
String s = count > 1 ? count + Chars.TIMES + previous : previous;
|
||||
stageName = stageName.equals("") ? s : stageName + "," + s;
|
||||
}
|
||||
|
||||
previous = current;
|
||||
count = 1;
|
||||
}
|
||||
}
|
||||
|
||||
if (previous != null) {
|
||||
String s = count > 1 ? "" + count + Chars.TIMES + previous : previous;
|
||||
stageName = stageName.equals("") ? s : stageName + "," + s;
|
||||
}
|
||||
|
||||
stages.add(stageName);
|
||||
}
|
||||
|
||||
for (int i = 0; i < stages.size(); i++) {
|
||||
String s = stages.get(i);
|
||||
if (s.equals("") && config.isStageActive(i)) {
|
||||
s = trans.get("Rocket.motorCount.noStageMotors");
|
||||
}
|
||||
|
||||
configurations.append(i == 0 ? s : "; " + s);
|
||||
}
|
||||
|
||||
return configurations.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns which string in input should be replaced, or null if no text needs to be replaced.
|
||||
* @param input The input string
|
||||
* @return The string to replace, or null if no text needs to be replaced.
|
||||
*/
|
||||
private static String getSubstiutionString(String input) {
|
||||
String[] content = getSubstitutionContent(input);
|
||||
if (content != null) {
|
||||
return content[0];
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Fills in the content of the substitution tag and the separator.
|
||||
* If there are both a motor and a manufacturer substitution tag, the array will contain the following:
|
||||
* [0] = The full tag, including substitution start and end
|
||||
* [1] = The motor/manufacturer substitution tag, depending on which one was found first.
|
||||
* if there are two substitution tags, the array will also contain the following:
|
||||
* ([2] = The separator)
|
||||
* ([3] = The motor/manufacturer substitution tag, depending on which one was found first.)
|
||||
* @param input The input string
|
||||
* @return The content of the substitution tag and the separator, or null if no text needs to be replaced.
|
||||
*/
|
||||
private static String[] getSubstitutionContent(String input) {
|
||||
// First try with only the motors tag
|
||||
String pattern = "\\" + SUBSTITUTION_START + "(" + SUBSTITUTION_MOTORS + ")" + "\\" + SUBSTITUTION_END;
|
||||
Pattern regexPattern = Pattern.compile(pattern);
|
||||
Matcher matcher = regexPattern.matcher(input);
|
||||
if (matcher.find()) {
|
||||
String[] content = new String[2];
|
||||
content[0] = matcher.group(0);
|
||||
content[1] = matcher.group(1);
|
||||
return content;
|
||||
}
|
||||
// First try with only the manufacturers tag
|
||||
pattern = "\\" + SUBSTITUTION_START + "(" + SUBSTITUTION_MANUFACTURERS + ")" + "\\" + SUBSTITUTION_END;
|
||||
regexPattern = Pattern.compile(pattern);
|
||||
matcher = regexPattern.matcher(input);
|
||||
if (matcher.find()) {
|
||||
String[] content = new String[2];
|
||||
content[0] = matcher.group(0);
|
||||
content[1] = matcher.group(1);
|
||||
return content;
|
||||
}
|
||||
|
||||
// Then try combined patterns
|
||||
pattern = SUBSTITUTION_PATTERN;
|
||||
regexPattern = Pattern.compile(pattern);
|
||||
matcher = regexPattern.matcher(input);
|
||||
if (matcher.find()) {
|
||||
String[] content = new String[4];
|
||||
content[0] = matcher.group(0);
|
||||
content[1] = matcher.group(1);
|
||||
if (matcher.groupCount() >= 3) {
|
||||
content[2] = matcher.group(2);
|
||||
content[3] = matcher.group(3);
|
||||
for (int i = 4; i < matcher.groupCount(); i++) {
|
||||
content[3] += matcher.group(i);
|
||||
}
|
||||
}
|
||||
return content;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
@ -1,158 +0,0 @@
|
||||
package net.sf.openrocket.formatting;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import com.google.inject.Inject;
|
||||
|
||||
import net.sf.openrocket.l10n.Translator;
|
||||
import net.sf.openrocket.motor.Motor;
|
||||
import net.sf.openrocket.motor.MotorConfiguration;
|
||||
import net.sf.openrocket.plugin.Plugin;
|
||||
import net.sf.openrocket.rocketcomponent.AxialStage;
|
||||
import net.sf.openrocket.rocketcomponent.FlightConfigurationId;
|
||||
import net.sf.openrocket.rocketcomponent.MotorMount;
|
||||
import net.sf.openrocket.rocketcomponent.Rocket;
|
||||
import net.sf.openrocket.rocketcomponent.RocketComponent;
|
||||
import net.sf.openrocket.util.ArrayList;
|
||||
import net.sf.openrocket.util.Chars;
|
||||
|
||||
@Plugin
|
||||
public class MotorDescriptionSubstitutor implements RocketSubstitutor {
|
||||
public static final String SUBSTITUTION = "{motors}";
|
||||
|
||||
@Inject
|
||||
private Translator trans;
|
||||
|
||||
@Override
|
||||
public boolean containsSubstitution(String str) {
|
||||
return str.contains(SUBSTITUTION);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String substitute(String str, Rocket rocket, FlightConfigurationId configId) {
|
||||
String description = getMotorConfigurationDescription(rocket, configId);
|
||||
return str.replace(SUBSTITUTION, description);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<String, String> getDescriptions() {
|
||||
Map<String, String> desc = new HashMap<String, String>();
|
||||
desc.put(SUBSTITUTION, trans.get("MotorDescriptionSubstitutor.description"));
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
|
||||
public String getMotorConfigurationDescription(Rocket rocket, FlightConfigurationId fcid) {
|
||||
String name;
|
||||
int motorCount = 0;
|
||||
|
||||
// Generate the description
|
||||
|
||||
// First iterate over each stage and store the designations of each motor
|
||||
List<List<String>> list = new ArrayList<List<String>>();
|
||||
List<String> currentList = Collections.emptyList();
|
||||
|
||||
Iterator<RocketComponent> iterator = rocket.iterator();
|
||||
while (iterator.hasNext()) {
|
||||
RocketComponent c = iterator.next();
|
||||
|
||||
if (c instanceof AxialStage) {
|
||||
|
||||
currentList = new ArrayList<String>();
|
||||
list.add(currentList);
|
||||
|
||||
} else if (c instanceof MotorMount) {
|
||||
|
||||
MotorMount mount = (MotorMount) c;
|
||||
MotorConfiguration inst = mount.getMotorConfig(fcid);
|
||||
Motor motor = inst.getMotor();
|
||||
|
||||
if (mount.isMotorMount() && motor != null) {
|
||||
String designation = motor.getDesignation(inst.getEjectionDelay());
|
||||
|
||||
for (int i = 0; i < mount.getMotorCount(); i++) {
|
||||
currentList.add(designation);
|
||||
motorCount++;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
if (motorCount == 0) {
|
||||
return trans.get("Rocket.motorCount.Nomotor");
|
||||
}
|
||||
|
||||
// Change multiple occurrences of a motor to n x motor
|
||||
List<String> stages = new ArrayList<String>();
|
||||
|
||||
for (List<String> stage : list) {
|
||||
String stageName = "";
|
||||
String previous = null;
|
||||
int count = 0;
|
||||
|
||||
Collections.sort(stage);
|
||||
for (String current : stage) {
|
||||
if (current.equals(previous)) {
|
||||
|
||||
count++;
|
||||
|
||||
} else {
|
||||
|
||||
if (previous != null) {
|
||||
String s = "";
|
||||
if (count > 1) {
|
||||
s = "" + count + Chars.TIMES + previous;
|
||||
} else {
|
||||
s = previous;
|
||||
}
|
||||
|
||||
if (stageName.equals(""))
|
||||
stageName = s;
|
||||
else
|
||||
stageName = stageName + "," + s;
|
||||
}
|
||||
|
||||
previous = current;
|
||||
count = 1;
|
||||
|
||||
}
|
||||
}
|
||||
if (previous != null) {
|
||||
String s = "";
|
||||
if (count > 1) {
|
||||
s = "" + count + Chars.TIMES + previous;
|
||||
} else {
|
||||
s = previous;
|
||||
}
|
||||
|
||||
if (stageName.equals(""))
|
||||
stageName = s;
|
||||
else
|
||||
stageName = stageName + "," + s;
|
||||
}
|
||||
|
||||
stages.add(stageName);
|
||||
}
|
||||
|
||||
name = "";
|
||||
for (int i = 0; i < stages.size(); i++) {
|
||||
String s = stages.get(i);
|
||||
if (s.equals(""))
|
||||
s = trans.get("Rocket.motorCount.noStageMotors");
|
||||
if (i == 0)
|
||||
name = name + s;
|
||||
else
|
||||
name = name + "; " + s;
|
||||
}
|
||||
return name;
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
@ -8,6 +8,7 @@ import java.util.Map;
|
||||
import java.util.Queue;
|
||||
import java.util.concurrent.ConcurrentLinkedQueue;
|
||||
|
||||
import net.sf.openrocket.formatting.RocketDescriptor;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
@ -36,6 +37,7 @@ public class FlightConfiguration implements FlightConfigurableParameter<FlightCo
|
||||
|
||||
private String configurationName;
|
||||
public static String DEFAULT_CONFIG_NAME = "[{motors}]";
|
||||
private final RocketDescriptor descriptor = Application.getInjector().getInstance(RocketDescriptor.class);
|
||||
|
||||
protected final Rocket rocket;
|
||||
protected final FlightConfigurationId fcid;
|
||||
@ -566,9 +568,9 @@ public class FlightConfiguration implements FlightConfigurableParameter<FlightCo
|
||||
*/
|
||||
public String getName() {
|
||||
if (configurationName == null) {
|
||||
return getOneLineMotorDescription();
|
||||
configurationName = DEFAULT_CONFIG_NAME;
|
||||
}
|
||||
return configurationName.replace(DEFAULT_CONFIG_NAME, getOneLineMotorDescription());
|
||||
return descriptor.format(configurationName, rocket, fcid);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -582,34 +584,6 @@ public class FlightConfiguration implements FlightConfigurableParameter<FlightCo
|
||||
}
|
||||
return configurationName;
|
||||
}
|
||||
|
||||
private String getOneLineMotorDescription(){
|
||||
StringBuilder buff = new StringBuilder("[");
|
||||
boolean first = true;
|
||||
int activeMotorCount = 0;
|
||||
for ( RocketComponent comp : getActiveComponents() ){
|
||||
if (( comp instanceof MotorMount )&&( ((MotorMount)comp).isMotorMount())){
|
||||
MotorMount mount = (MotorMount)comp;
|
||||
MotorConfiguration motorConfig = mount.getMotorConfig( fcid);
|
||||
|
||||
if( first ){
|
||||
first = false;
|
||||
}else{
|
||||
buff.append(";");
|
||||
}
|
||||
|
||||
if( ! motorConfig.isEmpty()){
|
||||
buff.append(motorConfig.toMotorCommonName());
|
||||
++activeMotorCount;
|
||||
}
|
||||
}
|
||||
}
|
||||
if( 0 == activeMotorCount ){
|
||||
return trans.get("noMotors");
|
||||
}
|
||||
buff.append("]");
|
||||
return buff.toString();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() { return this.getName(); }
|
||||
@ -932,7 +906,7 @@ public class FlightConfiguration implements FlightConfigurableParameter<FlightCo
|
||||
}
|
||||
|
||||
public String toDebug() {
|
||||
return this.fcid.toDebug()+" (#"+configurationInstanceId+") "+ getOneLineMotorDescription();
|
||||
return this.fcid.toDebug()+" (#"+configurationInstanceId+") "+ getName();
|
||||
}
|
||||
|
||||
// DEBUG / DEVEL
|
||||
|
@ -1296,6 +1296,11 @@ public abstract class RocketComponent implements ChangeSource, Cloneable, Iterab
|
||||
mutex.verify();
|
||||
return 0;
|
||||
}
|
||||
|
||||
public double getRadiusOffset(RadiusMethod method) {
|
||||
double radius = getRadiusMethod().getRadius(parent, this, getRadiusOffset());
|
||||
return method.getAsOffset(parent, this, radius);
|
||||
}
|
||||
|
||||
public RadiusMethod getRadiusMethod() {
|
||||
return RadiusMethod.COAXIAL;
|
||||
@ -2059,20 +2064,37 @@ public abstract class RocketComponent implements ChangeSource, Cloneable, Iterab
|
||||
}
|
||||
|
||||
/**
|
||||
* Return all the component assemblies that are a child of this component
|
||||
* @return list of ComponentAssembly components that are a child of this component
|
||||
* Return all the component assemblies that are a direct/indirect child of this component
|
||||
* @return list of ComponentAssembly components that are a direct/indirect child of this component
|
||||
*/
|
||||
public final List<RocketComponent> getChildAssemblies() {
|
||||
public final List<ComponentAssembly> getAllChildAssemblies() {
|
||||
checkState();
|
||||
|
||||
Iterator<RocketComponent> children = iterator(false);
|
||||
|
||||
List<RocketComponent> result = new ArrayList<>();
|
||||
List<ComponentAssembly> result = new ArrayList<>();
|
||||
|
||||
while (children.hasNext()) {
|
||||
RocketComponent child = children.next();
|
||||
if (child instanceof ComponentAssembly) {
|
||||
result.add(child);
|
||||
result.add((ComponentAssembly) child);
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return all the component assemblies that are a direct child of this component
|
||||
* @return list of ComponentAssembly components that are a direct child of this component
|
||||
*/
|
||||
public final List<ComponentAssembly> getDirectChildAssemblies() {
|
||||
checkState();
|
||||
|
||||
List<ComponentAssembly> result = new ArrayList<>();
|
||||
|
||||
for (RocketComponent child : this.getChildren()) {
|
||||
if (child instanceof ComponentAssembly) {
|
||||
result.add((ComponentAssembly) child);
|
||||
}
|
||||
}
|
||||
return result;
|
||||
|
@ -7,10 +7,10 @@ import java.util.Collection;
|
||||
import java.util.List;
|
||||
|
||||
import net.sf.openrocket.preset.ComponentPreset;
|
||||
import net.sf.openrocket.rocketcomponent.position.AxialMethod;
|
||||
import net.sf.openrocket.util.BoundingBox;
|
||||
import net.sf.openrocket.util.Coordinate;
|
||||
import net.sf.openrocket.util.MathUtil;
|
||||
import net.sf.openrocket.rocketcomponent.position.RadiusMethod;
|
||||
|
||||
/**
|
||||
* Class for an axially symmetric rocket component generated by rotating
|
||||
@ -622,7 +622,8 @@ public abstract class SymmetricComponent extends BodyComponent implements BoxBou
|
||||
while (0 <= searchSiblingIndex) {
|
||||
final RocketComponent searchSibling = searchParent.getChild(searchSiblingIndex);
|
||||
if ((searchSibling instanceof SymmetricComponent) && inline(searchSibling)) {
|
||||
return (SymmetricComponent) searchSibling;
|
||||
return getPreviousSymmetricComponentFromComponentAssembly((SymmetricComponent) searchSibling,
|
||||
(SymmetricComponent) searchSibling, 0);
|
||||
}
|
||||
--searchSiblingIndex;
|
||||
}
|
||||
@ -636,14 +637,81 @@ public abstract class SymmetricComponent extends BodyComponent implements BoxBou
|
||||
}
|
||||
}
|
||||
|
||||
// one last thing -- I could be the child of a PodSet, and in line with
|
||||
// one last thing -- I could be the child of a ComponentAssembly, and in line with
|
||||
// the SymmetricComponent that is my grandParent
|
||||
if ((grandParent instanceof SymmetricComponent) && inline(grandParent)) {
|
||||
return (SymmetricComponent) grandParent;
|
||||
// If the grandparent is actually before me, then this is the previous component
|
||||
if ((parent.getAxialOffset(AxialMethod.TOP) + getAxialOffset(AxialMethod.TOP)) > 0) {
|
||||
return (SymmetricComponent) grandParent;
|
||||
}
|
||||
// If not, then search for the component before the grandparent
|
||||
else {
|
||||
// NOTE: will be incorrect if the ComponentAssembly is even further to the front than the
|
||||
// previous component of the grandparent. But that would be really bad rocket design...
|
||||
return ((SymmetricComponent) grandParent).getPreviousSymmetricComponent();
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if parent has component assemblies that have potential previous components.
|
||||
* A child symmetric component of a component assembly is a potential previous component if:
|
||||
* - it is inline with the parent
|
||||
* - it is flush with the end of the parent
|
||||
* - it is larger in aft radius than the parent
|
||||
* @param parent parent component to check for child component assemblies
|
||||
* @param previous the current previous component candidate
|
||||
* @param flushOffset an extra offset to be added to check for flushness. This is used when recursively running this
|
||||
* method to check children of children of the original parent are flush with the end of the
|
||||
* original parent.
|
||||
* @return the previous component if it is found
|
||||
*/
|
||||
private SymmetricComponent getPreviousSymmetricComponentFromComponentAssembly(SymmetricComponent parent,
|
||||
SymmetricComponent previous, double flushOffset) {
|
||||
if (previous == null) {
|
||||
return parent;
|
||||
}
|
||||
if (parent == null) {
|
||||
return previous;
|
||||
}
|
||||
|
||||
double maxRadius = previous.isAftRadiusAutomatic() ? 0 : previous.getAftRadius();
|
||||
SymmetricComponent previousComponent = previous;
|
||||
for (ComponentAssembly assembly : parent.getDirectChildAssemblies()) {
|
||||
if (assembly.getChildCount() == 0) {
|
||||
continue;
|
||||
}
|
||||
/*
|
||||
* Check if the component assembly's last child is a symmetric component that is:
|
||||
* - inline with the parent
|
||||
* - flush with the end of the parent
|
||||
* - larger in aft radius than the parent
|
||||
* in that case, this component assembly is the new previousComponent.
|
||||
*/
|
||||
RocketComponent lastChild = assembly.getChild(assembly.getChildCount() - 1);
|
||||
if (!( (lastChild instanceof SymmetricComponent) && parent.inline(lastChild) )) {
|
||||
continue;
|
||||
}
|
||||
SymmetricComponent lastSymmetricChild = (SymmetricComponent) lastChild;
|
||||
double flushDeviation = flushOffset + assembly.getAxialOffset(AxialMethod.BOTTOM); // How much the last child is flush with the parent
|
||||
|
||||
// If the last symmetric child from the assembly if flush with the end of the parent and larger than the
|
||||
// current previous component, then this is the new previous component
|
||||
if (MathUtil.equals(flushDeviation, 0) && !lastSymmetricChild.isAftRadiusAutomatic() &&
|
||||
lastSymmetricChild.getAftRadius() > maxRadius) {
|
||||
previousComponent = lastSymmetricChild;
|
||||
maxRadius = previousComponent.getAftRadius();
|
||||
}
|
||||
// It could be that there is a child component assembly that is flush with the end of the parent or larger
|
||||
// Recursively check assembly's children
|
||||
previousComponent = getPreviousSymmetricComponentFromComponentAssembly(lastSymmetricChild, previousComponent, flushDeviation);
|
||||
maxRadius = previousComponent != null ? previousComponent.getAftRadius() : maxRadius;
|
||||
}
|
||||
|
||||
return previousComponent;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the next symmetric component, or null if none exists.
|
||||
@ -670,7 +738,8 @@ public abstract class SymmetricComponent extends BodyComponent implements BoxBou
|
||||
while (searchSiblingIndex < searchParent.getChildCount()) {
|
||||
final RocketComponent searchSibling = searchParent.getChild(searchSiblingIndex);
|
||||
if ((searchSibling instanceof SymmetricComponent) && inline(searchSibling)) {
|
||||
return (SymmetricComponent) searchSibling;
|
||||
return getNextSymmetricComponentFromComponentAssembly((SymmetricComponent) searchSibling,
|
||||
(SymmetricComponent) searchSibling, 0);
|
||||
}
|
||||
++searchSiblingIndex;
|
||||
}
|
||||
@ -681,13 +750,22 @@ public abstract class SymmetricComponent extends BodyComponent implements BoxBou
|
||||
searchSiblingIndex = 0;
|
||||
}
|
||||
|
||||
// One last thing -- I could have a child that is a PodSet that is in line
|
||||
// One last thing -- I could have a child that is a ComponentAssembly that is in line
|
||||
// with me
|
||||
for (RocketComponent child : getChildren()) {
|
||||
if (child instanceof PodSet) {
|
||||
if (child instanceof ComponentAssembly) {
|
||||
for (RocketComponent grandchild : child.getChildren()) {
|
||||
if ((grandchild instanceof SymmetricComponent) && inline(grandchild)) {
|
||||
return (SymmetricComponent) grandchild;
|
||||
// If the grandparent is actually after me, then this is the next component
|
||||
if ((parent.getAxialOffset(AxialMethod.BOTTOM) + getAxialOffset(AxialMethod.BOTTOM)) < 0) {
|
||||
return (SymmetricComponent) grandchild;
|
||||
}
|
||||
// If not, then search for the component after the grandparent
|
||||
else {
|
||||
// NOTE: will be incorrect if the ComponentAssembly is even further to the back than the
|
||||
// next component of the grandparent. But that would be really bad rocket design...
|
||||
return ((SymmetricComponent) grandchild).getNextSymmetricComponent();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -696,6 +774,64 @@ public abstract class SymmetricComponent extends BodyComponent implements BoxBou
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if parent has component assemblies that have potential next components.
|
||||
* A child symmetric component of a component assembly is a potential next component if:
|
||||
* - it is inline with the parent
|
||||
* - it is flush with the front of the parent
|
||||
* - it is larger in fore radius than the parent
|
||||
* @param parent parent component to check for child component assemblies
|
||||
* @param next the next previous component candidate
|
||||
* @param flushOffset an extra offset to be added to check for flushness. This is used when recursively running this
|
||||
* method to check children of children of the original parent are flush with the front of the
|
||||
* original parent.
|
||||
* @return the next component if it is found
|
||||
*/
|
||||
private SymmetricComponent getNextSymmetricComponentFromComponentAssembly(SymmetricComponent parent,
|
||||
SymmetricComponent next, double flushOffset) {
|
||||
if (next == null) {
|
||||
return parent;
|
||||
}
|
||||
if (parent == null) {
|
||||
return next;
|
||||
}
|
||||
|
||||
double maxRadius = next.isForeRadiusAutomatic() ? 0 : next.getForeRadius();
|
||||
SymmetricComponent nextComponent = next;
|
||||
for (ComponentAssembly assembly : parent.getDirectChildAssemblies()) {
|
||||
if (assembly.getChildCount() == 0) {
|
||||
continue;
|
||||
}
|
||||
/*
|
||||
* Check if the component assembly's last child is a symmetric component that is:
|
||||
* - inline with the parent
|
||||
* - flush with the front of the parent
|
||||
* - larger in fore radius than the parent
|
||||
* in that case, this component assembly is the new nextComponent.
|
||||
*/
|
||||
RocketComponent firstChild = assembly.getChild(0);
|
||||
if (!( (firstChild instanceof SymmetricComponent) && parent.inline(firstChild) )) {
|
||||
continue;
|
||||
}
|
||||
SymmetricComponent firstSymmetricChild = (SymmetricComponent) firstChild;
|
||||
double flushDeviation = flushOffset + assembly.getAxialOffset(AxialMethod.TOP); // How much the last child is flush with the parent
|
||||
|
||||
// If the first symmetric child from the assembly if flush with the front of the parent and larger than the
|
||||
// current next component, then this is the new next component
|
||||
if (MathUtil.equals(flushDeviation, 0) && !firstSymmetricChild.isForeRadiusAutomatic() &&
|
||||
firstSymmetricChild.getForeRadius() > maxRadius) {
|
||||
nextComponent = firstSymmetricChild;
|
||||
maxRadius = nextComponent.getForeRadius();
|
||||
}
|
||||
// It could be that there is a child component assembly that is flush with the front of the parent or larger
|
||||
// Recursively check assembly's children
|
||||
nextComponent = getNextSymmetricComponentFromComponentAssembly(firstSymmetricChild, nextComponent, flushDeviation);
|
||||
maxRadius = nextComponent != null ? nextComponent.getForeRadius() : maxRadius;
|
||||
}
|
||||
|
||||
return nextComponent;
|
||||
}
|
||||
|
||||
/***
|
||||
* Determine whether a candidate symmetric component is in line with us
|
||||
*
|
||||
|
@ -10,7 +10,7 @@ public enum RadiusMethod implements DistanceMethod {
|
||||
// just as a reminder:
|
||||
// public T[] getEnumConstants()
|
||||
|
||||
// both components are on the same axis
|
||||
// Same axis as the target component
|
||||
COAXIAL ( Application.getTranslator().get("RocketComponent.Position.Method.Radius.COAXIAL") ){
|
||||
@Override
|
||||
public double getRadius( final RocketComponent parentComponent, final RocketComponent thisComponent, final double requestedOffset ){
|
||||
@ -22,7 +22,8 @@ public enum RadiusMethod implements DistanceMethod {
|
||||
return 0;
|
||||
}
|
||||
},
|
||||
|
||||
|
||||
// Center of the parent component
|
||||
FREE(Application.getTranslator().get("RocketComponent.Position.Method.Radius.FREE") ){
|
||||
@Override
|
||||
public boolean clampToZero() { return false; }
|
||||
@ -37,7 +38,8 @@ public enum RadiusMethod implements DistanceMethod {
|
||||
return radius;
|
||||
}
|
||||
},
|
||||
|
||||
|
||||
// Surface of the parent component
|
||||
RELATIVE ( Application.getTranslator().get("RocketComponent.Position.Method.Radius.RELATIVE") ){
|
||||
@Override
|
||||
public boolean clampToZero() { return false; }
|
||||
|
@ -469,7 +469,6 @@ public class BarrowmanCalculatorTest {
|
||||
final FlightConfiguration testConfig = testRocket.getSelectedConfiguration();
|
||||
final FlightConditions testConditions = new FlightConditions(testConfig);
|
||||
|
||||
TestRockets.dumpRocket(testRocket, "/home/joseph/rockets/openrocket/git/openrocket/work/testrocket.ork");
|
||||
final BarrowmanCalculator testCalc = new BarrowmanCalculator();
|
||||
double testCP = testCalc.getCP(testConfig, testConditions, warnings).x;
|
||||
final AerodynamicForces testForces = testCalc.getAerodynamicForces(testConfig, testConditions, warnings);
|
||||
@ -483,13 +482,19 @@ public class BarrowmanCalculatorTest {
|
||||
// move the pod back.
|
||||
pod.setAxialOffset(pod.getAxialOffset() + 0.1);
|
||||
testCP = testCalc.getCP(testConfig, testConditions, warnings).x;
|
||||
assertFalse("should be warning from gap in airframe", warnings.isEmpty());
|
||||
assertEquals("should be warning from gap in airframe", 1, warnings.size());
|
||||
|
||||
// move the pod forward.
|
||||
warnings.clear();
|
||||
pod.setAxialOffset(pod.getAxialOffset() - 0.2);
|
||||
testCP = testCalc.getCP(testConfig, testConditions, warnings).x;
|
||||
assertFalse("should be warning from airframe overlap", warnings.isEmpty());
|
||||
pod.setAxialOffset(pod.getAxialOffset() - 0.3);
|
||||
testCP = testCalc.getCP(testConfig, testConditions, warnings).x;
|
||||
assertEquals("should be warning from airframe overlap", 1, warnings.size());
|
||||
|
||||
// move the pod back.
|
||||
warnings.clear();
|
||||
pod.setAxialOffset(pod.getAxialOffset() + 0.1);
|
||||
testCP = testCalc.getCP(testConfig, testConditions, warnings).x;
|
||||
assertEquals("should be warning from podset airframe overlap", 1, warnings.size());
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -580,10 +580,114 @@ public class FlightConfigurationTest extends BaseTestCase {
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testName() {
|
||||
Rocket rocket = TestRockets.makeFalcon9Heavy();
|
||||
FlightConfiguration selected = rocket.getSelectedConfiguration();
|
||||
|
||||
// Test only motors or only manufacturers
|
||||
selected.setName("[{motors}] - [{manufacturers}]");
|
||||
|
||||
selected.setAllStages();
|
||||
assertEquals("[[Rocket.motorCount.noStageMotors]; M1350-0; 4\u00D7G77-0] - [[Rocket.motorCount.noStageMotors]; AeroTech; 4\u00D7AeroTech]", selected.getName());
|
||||
|
||||
selected.setOnlyStage(0);
|
||||
assertEquals("[[Rocket.motorCount.Nomotor]] - [[Rocket.motorCount.Nomotor]]", selected.getName());
|
||||
|
||||
selected.setOnlyStage(1);
|
||||
assertEquals("[; M1350-0; ] - [; AeroTech; ]", selected.getName());
|
||||
|
||||
selected.setAllStages();
|
||||
selected._setStageActive(0, false);
|
||||
assertEquals("[; M1350-0; 4\u00D7G77-0] - [; AeroTech; 4\u00D7AeroTech]", selected.getName());
|
||||
|
||||
|
||||
// Test combination of motors and manufacturers
|
||||
selected.setName("[{motors manufacturers}] -- [{manufacturers}] - [{motors}]");
|
||||
|
||||
selected.setAllStages();
|
||||
assertEquals("[[Rocket.motorCount.noStageMotors]; M1350-0 AeroTech; 4\u00D7G77-0 AeroTech] -- [[Rocket.motorCount.noStageMotors]; AeroTech; 4\u00D7AeroTech] - [[Rocket.motorCount.noStageMotors]; M1350-0; 4\u00D7G77-0]", selected.getName());
|
||||
|
||||
selected.setOnlyStage(0);
|
||||
assertEquals("[[Rocket.motorCount.Nomotor]] -- [[Rocket.motorCount.Nomotor]] - [[Rocket.motorCount.Nomotor]]", selected.getName());
|
||||
|
||||
selected.setOnlyStage(1);
|
||||
assertEquals("[; M1350-0 AeroTech; ] -- [; AeroTech; ] - [; M1350-0; ]", selected.getName());
|
||||
|
||||
selected.setAllStages();
|
||||
selected._setStageActive(0, false);
|
||||
assertEquals("[; M1350-0 AeroTech; 4\u00D7G77-0 AeroTech] -- [; AeroTech; 4\u00D7AeroTech] - [; M1350-0; 4\u00D7G77-0]", selected.getName());
|
||||
|
||||
// Test combination of manufacturers and motors
|
||||
selected.setName("[{manufacturers | motors}]");
|
||||
|
||||
selected.setAllStages();
|
||||
assertEquals("[[Rocket.motorCount.noStageMotors]; AeroTech | M1350-0; 4\u00D7AeroTech | G77-0]", selected.getName());
|
||||
|
||||
selected.setOnlyStage(0);
|
||||
assertEquals("[[Rocket.motorCount.Nomotor]]", selected.getName());
|
||||
|
||||
selected.setOnlyStage(1);
|
||||
assertEquals("[; AeroTech | M1350-0; ]", selected.getName());
|
||||
|
||||
selected.setAllStages();
|
||||
selected._setStageActive(0, false);
|
||||
assertEquals("[; AeroTech | M1350-0; 4\u00D7AeroTech | G77-0]", selected.getName());
|
||||
|
||||
// Test empty tags
|
||||
selected.setName("{}");
|
||||
|
||||
selected.setAllStages();
|
||||
assertEquals("{}", selected.getName());
|
||||
|
||||
selected.setOnlyStage(0);
|
||||
assertEquals("{}", selected.getName());
|
||||
|
||||
selected.setOnlyStage(1);
|
||||
assertEquals("{}", selected.getName());
|
||||
|
||||
selected.setAllStages();
|
||||
selected._setStageActive(0, false);
|
||||
assertEquals("{}", selected.getName());
|
||||
|
||||
// Test invalid tags (1)
|
||||
selected.setName("{motorsm}");
|
||||
|
||||
selected.setAllStages();
|
||||
assertEquals("{motorsm}", selected.getName());
|
||||
|
||||
selected.setOnlyStage(0);
|
||||
assertEquals("{motorsm}", selected.getName());
|
||||
|
||||
selected.setOnlyStage(1);
|
||||
assertEquals("{motorsm}", selected.getName());
|
||||
|
||||
selected.setAllStages();
|
||||
selected._setStageActive(0, false);
|
||||
assertEquals("{motorsm}", selected.getName());
|
||||
|
||||
// Test invalid tags (2)
|
||||
selected.setName("{motors manufacturers '}");
|
||||
|
||||
selected.setAllStages();
|
||||
assertEquals("{motors manufacturers '}", selected.getName());
|
||||
|
||||
selected.setOnlyStage(0);
|
||||
assertEquals("{motors manufacturers '}", selected.getName());
|
||||
|
||||
selected.setOnlyStage(1);
|
||||
assertEquals("{motors manufacturers '}", selected.getName());
|
||||
|
||||
selected.setAllStages();
|
||||
selected._setStageActive(0, false);
|
||||
assertEquals("{motors manufacturers '}", selected.getName());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCopy() throws NoSuchFieldException, IllegalAccessException {
|
||||
Rocket rocket = TestRockets.makeFalcon9Heavy();
|
||||
FlightConfiguration original = rocket.getSelectedConfiguration();
|
||||
original.setName("[{motors}] - [{manufacturers}]");
|
||||
original.setOnlyStage(0);
|
||||
|
||||
// vvvv Test Target vvvv
|
||||
|
@ -0,0 +1,509 @@
|
||||
package net.sf.openrocket.rocketcomponent;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertNull;
|
||||
import net.sf.openrocket.rocketcomponent.position.AxialMethod;
|
||||
import net.sf.openrocket.rocketcomponent.position.RadiusMethod;
|
||||
import net.sf.openrocket.util.BaseTestCase.BaseTestCase;
|
||||
|
||||
import net.sf.openrocket.util.TestRockets;
|
||||
import org.junit.Test;
|
||||
|
||||
public class SymmetricComponentTest extends BaseTestCase {
|
||||
|
||||
@Test
|
||||
public void testPreviousSymmetricComponent() {
|
||||
Rocket rocket = TestRockets.makeFalcon9Heavy();
|
||||
AxialStage payloadStage = rocket.getStage(0);
|
||||
NoseCone payloadFairingNoseCone = (NoseCone) payloadStage.getChild(0);
|
||||
BodyTube payloadBody = (BodyTube) payloadStage.getChild(1);
|
||||
Transition payloadFairingTail = (Transition) payloadStage.getChild(2);
|
||||
BodyTube upperStageBody = (BodyTube) payloadStage.getChild(3);
|
||||
BodyTube interstageBody = (BodyTube) payloadStage.getChild(4);
|
||||
|
||||
assertNull(payloadFairingNoseCone.getPreviousSymmetricComponent());
|
||||
assertEquals(payloadFairingNoseCone, payloadBody.getPreviousSymmetricComponent());
|
||||
assertEquals(payloadBody, payloadFairingTail.getPreviousSymmetricComponent());
|
||||
assertEquals(payloadFairingTail, upperStageBody.getPreviousSymmetricComponent());
|
||||
assertEquals(upperStageBody, interstageBody.getPreviousSymmetricComponent());
|
||||
|
||||
AxialStage coreStage = rocket.getStage(1);
|
||||
BodyTube coreBody = (BodyTube) coreStage.getChild(0);
|
||||
|
||||
assertEquals(interstageBody, coreBody.getPreviousSymmetricComponent());
|
||||
|
||||
ParallelStage boosterStage = (ParallelStage) rocket.getStage(2);
|
||||
NoseCone boosterCone = (NoseCone) boosterStage.getChild(0);
|
||||
BodyTube boosterBody = (BodyTube) boosterStage.getChild(1);
|
||||
|
||||
assertNull(boosterCone.getPreviousSymmetricComponent());
|
||||
assertEquals(boosterCone, boosterBody.getPreviousSymmetricComponent());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testPreviousSymmetricComponentInlineComponentAssembly() {
|
||||
Rocket rocket = TestRockets.makeFalcon9Heavy();
|
||||
|
||||
// Stage 0
|
||||
AxialStage payloadStage = rocket.getStage(0);
|
||||
NoseCone payloadFairingNoseCone = (NoseCone) payloadStage.getChild(0);
|
||||
BodyTube payloadBody = (BodyTube) payloadStage.getChild(1);
|
||||
Transition payloadFairingTail = (Transition) payloadStage.getChild(2);
|
||||
BodyTube upperStageBody = (BodyTube) payloadStage.getChild(3);
|
||||
BodyTube interstageBody = (BodyTube) payloadStage.getChild(4);
|
||||
|
||||
// Stage 1
|
||||
AxialStage coreStage = rocket.getStage(1);
|
||||
BodyTube coreBody = (BodyTube) coreStage.getChild(0);
|
||||
|
||||
// Booster stage
|
||||
ParallelStage boosterStage = (ParallelStage) rocket.getStage(2);
|
||||
boosterStage.setInstanceCount(1);
|
||||
boosterStage.setRadius(RadiusMethod.RELATIVE, 0);
|
||||
NoseCone boosterCone = (NoseCone) boosterStage.getChild(0);
|
||||
BodyTube boosterBody = (BodyTube) boosterStage.getChild(1);
|
||||
|
||||
// Add inline pod set
|
||||
PodSet podSet = new PodSet();
|
||||
podSet.setName("Inline Pod Set");
|
||||
podSet.setInstanceCount(1);
|
||||
podSet.setRadius(RadiusMethod.FREE, 0);
|
||||
coreBody.addChild(podSet);
|
||||
podSet.setAxialOffset(AxialMethod.BOTTOM, 0);
|
||||
NoseCone podSetCone = new NoseCone();
|
||||
podSetCone.setLength(0.1);
|
||||
podSetCone.setBaseRadius(0.05);
|
||||
podSet.addChild(podSetCone);
|
||||
BodyTube podSetBody = new BodyTube(0.2, 0.05, 0.001);
|
||||
podSetBody.setName("Pod Set Body");
|
||||
podSet.addChild(podSetBody);
|
||||
TrapezoidFinSet finSet = new TrapezoidFinSet();
|
||||
podSetBody.addChild(finSet);
|
||||
|
||||
// Add last stage
|
||||
AxialStage lastStage = new AxialStage();
|
||||
BodyTube lastStageBody = new BodyTube(0.2, 0.05, 0.001);
|
||||
lastStageBody.setName("Last Stage Body");
|
||||
lastStage.addChild(lastStageBody);
|
||||
rocket.addChild(lastStage);
|
||||
|
||||
assertNull(payloadFairingNoseCone.getPreviousSymmetricComponent());
|
||||
assertEquals(payloadFairingNoseCone, payloadBody.getPreviousSymmetricComponent());
|
||||
assertEquals(payloadBody, payloadFairingTail.getPreviousSymmetricComponent());
|
||||
assertEquals(payloadFairingTail, upperStageBody.getPreviousSymmetricComponent());
|
||||
assertEquals(upperStageBody, interstageBody.getPreviousSymmetricComponent());
|
||||
|
||||
assertNull(boosterCone.getPreviousSymmetricComponent());
|
||||
assertEquals(boosterCone, boosterBody.getPreviousSymmetricComponent());
|
||||
|
||||
// case 1: pod set is larger, and at the back of the core stage
|
||||
assertEquals(podSetBody, lastStageBody.getPreviousSymmetricComponent());
|
||||
assertEquals(coreBody, podSetCone.getPreviousSymmetricComponent());
|
||||
assertEquals(podSetCone, podSetBody.getPreviousSymmetricComponent());
|
||||
assertEquals(interstageBody, coreBody.getPreviousSymmetricComponent());
|
||||
|
||||
// case 2: pod set is smaller, and at the back of the core stage
|
||||
podSetBody.setOuterRadius(0.02);
|
||||
assertEquals(coreBody, lastStageBody.getPreviousSymmetricComponent());
|
||||
assertEquals(coreBody, podSetCone.getPreviousSymmetricComponent());
|
||||
assertEquals(podSetCone, podSetBody.getPreviousSymmetricComponent());
|
||||
assertEquals(interstageBody, coreBody.getPreviousSymmetricComponent());
|
||||
|
||||
// case 3: pod set is equal, and at the back of the core stage
|
||||
podSetBody.setOuterRadius(0.0385);
|
||||
assertEquals(coreBody, lastStageBody.getPreviousSymmetricComponent());
|
||||
assertEquals(coreBody, podSetCone.getPreviousSymmetricComponent());
|
||||
assertEquals(podSetCone, podSetBody.getPreviousSymmetricComponent());
|
||||
assertEquals(interstageBody, coreBody.getPreviousSymmetricComponent());
|
||||
|
||||
// case 4: pod set is larger, and at the front of the core stage
|
||||
podSetBody.setOuterRadius(0.05);
|
||||
podSet.setAxialOffset(AxialMethod.TOP, 0);
|
||||
assertEquals(coreBody, lastStageBody.getPreviousSymmetricComponent());
|
||||
assertEquals(interstageBody, podSetCone.getPreviousSymmetricComponent());
|
||||
assertEquals(podSetCone, podSetBody.getPreviousSymmetricComponent());
|
||||
assertEquals(interstageBody, coreBody.getPreviousSymmetricComponent());
|
||||
|
||||
// case 5: pod set is smaller, and at the front of the core stage
|
||||
podSetBody.setOuterRadius(0.02);
|
||||
assertEquals(coreBody, lastStageBody.getPreviousSymmetricComponent());
|
||||
assertEquals(interstageBody, podSetCone.getPreviousSymmetricComponent());
|
||||
assertEquals(podSetCone, podSetBody.getPreviousSymmetricComponent());
|
||||
assertEquals(interstageBody, coreBody.getPreviousSymmetricComponent());
|
||||
|
||||
// case 6: pod set is equal, and at the front of the core stage
|
||||
podSetBody.setOuterRadius(0.0385);
|
||||
assertEquals(coreBody, lastStageBody.getPreviousSymmetricComponent());
|
||||
assertEquals(interstageBody, podSetCone.getPreviousSymmetricComponent());
|
||||
assertEquals(podSetCone, podSetBody.getPreviousSymmetricComponent());
|
||||
assertEquals(interstageBody, coreBody.getPreviousSymmetricComponent());
|
||||
|
||||
// case 7: pod set is same length as core stage, and larger, and at the front of the core stage
|
||||
podSetBody.setOuterRadius(0.05);
|
||||
podSetBody.setLength(0.7);
|
||||
assertEquals(podSetBody, lastStageBody.getPreviousSymmetricComponent());
|
||||
assertEquals(interstageBody, podSetCone.getPreviousSymmetricComponent());
|
||||
assertEquals(podSetCone, podSetBody.getPreviousSymmetricComponent());
|
||||
assertEquals(interstageBody, coreBody.getPreviousSymmetricComponent());
|
||||
|
||||
// case 8: pod set is same length as core stage, and smaller, and at the front of the core stage
|
||||
podSetBody.setOuterRadius(0.02);
|
||||
assertEquals(coreBody, lastStageBody.getPreviousSymmetricComponent());
|
||||
assertEquals(interstageBody, podSetCone.getPreviousSymmetricComponent());
|
||||
assertEquals(podSetCone, podSetBody.getPreviousSymmetricComponent());
|
||||
assertEquals(interstageBody, coreBody.getPreviousSymmetricComponent());
|
||||
|
||||
// case 9: pod set is in larger, and in the middle of the core stage
|
||||
podSetBody.setLength(0.2);
|
||||
podSetBody.setOuterRadius(0.05);
|
||||
podSet.setAxialOffset(AxialMethod.MIDDLE, 0);
|
||||
assertEquals(coreBody, lastStageBody.getPreviousSymmetricComponent());
|
||||
assertEquals(coreBody, podSetCone.getPreviousSymmetricComponent());
|
||||
assertEquals(podSetCone, podSetBody.getPreviousSymmetricComponent());
|
||||
assertEquals(interstageBody, coreBody.getPreviousSymmetricComponent());
|
||||
|
||||
// case 10: pod set is in larger, and behind the back of the core stage
|
||||
podSet.setAxialOffset(AxialMethod.BOTTOM, 1);
|
||||
assertEquals(coreBody, lastStageBody.getPreviousSymmetricComponent());
|
||||
assertEquals(coreBody, podSetCone.getPreviousSymmetricComponent());
|
||||
assertEquals(podSetCone, podSetBody.getPreviousSymmetricComponent());
|
||||
assertEquals(interstageBody, coreBody.getPreviousSymmetricComponent());
|
||||
|
||||
// Add a booster inside the pod set
|
||||
ParallelStage insideBooster = new ParallelStage();
|
||||
insideBooster.setName("Inside Booster");
|
||||
insideBooster.setInstanceCount(1);
|
||||
insideBooster.setRadius(RadiusMethod.FREE, 0);
|
||||
podSetBody.addChild(insideBooster);
|
||||
insideBooster.setAxialOffset(AxialMethod.BOTTOM, 0);
|
||||
BodyTube insideBoosterBody = new BodyTube(0.2, 0.06, 0.001);
|
||||
insideBoosterBody.setName("Inside Booster Body");
|
||||
insideBooster.addChild(insideBoosterBody);
|
||||
|
||||
// Case 1: inside booster is larger than pod set and flush to its end (both are at the back of the core stage)
|
||||
podSet.setAxialOffset(AxialMethod.BOTTOM, 0);
|
||||
insideBoosterBody.setOuterRadius(0.06);
|
||||
assertEquals(insideBoosterBody, lastStageBody.getPreviousSymmetricComponent());
|
||||
assertEquals(coreBody, podSetCone.getPreviousSymmetricComponent());
|
||||
assertEquals(podSetCone, podSetBody.getPreviousSymmetricComponent());
|
||||
assertEquals(interstageBody, coreBody.getPreviousSymmetricComponent());
|
||||
assertEquals(podSetCone, insideBoosterBody.getPreviousSymmetricComponent());
|
||||
|
||||
// Case 2: inside booster is smaller than pod set and flush to its end
|
||||
insideBoosterBody.setOuterRadius(0.04);
|
||||
assertEquals(podSetBody, lastStageBody.getPreviousSymmetricComponent());
|
||||
assertEquals(coreBody, podSetCone.getPreviousSymmetricComponent());
|
||||
assertEquals(podSetCone, podSetBody.getPreviousSymmetricComponent());
|
||||
assertEquals(interstageBody, coreBody.getPreviousSymmetricComponent());
|
||||
assertEquals(podSetCone, insideBoosterBody.getPreviousSymmetricComponent());
|
||||
|
||||
// Case 3: inside booster is equal the pod set and flush to its end
|
||||
insideBoosterBody.setOuterRadius(0.05);
|
||||
assertEquals(podSetBody, lastStageBody.getPreviousSymmetricComponent());
|
||||
assertEquals(coreBody, podSetCone.getPreviousSymmetricComponent());
|
||||
assertEquals(podSetCone, podSetBody.getPreviousSymmetricComponent());
|
||||
assertEquals(interstageBody, coreBody.getPreviousSymmetricComponent());
|
||||
assertEquals(podSetCone, insideBoosterBody.getPreviousSymmetricComponent());
|
||||
|
||||
// Case 4: inside booster is larger than pod set and before the back (pod set at the back of the core stage)
|
||||
insideBooster.setAxialOffset(AxialMethod.BOTTOM, -1);
|
||||
insideBoosterBody.setOuterRadius(0.06);
|
||||
assertEquals(podSetBody, lastStageBody.getPreviousSymmetricComponent());
|
||||
assertEquals(coreBody, podSetCone.getPreviousSymmetricComponent());
|
||||
assertEquals(podSetCone, podSetBody.getPreviousSymmetricComponent());
|
||||
assertEquals(interstageBody, coreBody.getPreviousSymmetricComponent());
|
||||
assertEquals(podSetCone, insideBoosterBody.getPreviousSymmetricComponent());
|
||||
|
||||
// Case 5: inside booster is larger than pod set and after the back (pod set at the back of the core stage)
|
||||
insideBooster.setAxialOffset(AxialMethod.BOTTOM, 1);
|
||||
assertEquals(podSetBody, lastStageBody.getPreviousSymmetricComponent());
|
||||
assertEquals(coreBody, podSetCone.getPreviousSymmetricComponent());
|
||||
assertEquals(podSetCone, podSetBody.getPreviousSymmetricComponent());
|
||||
assertEquals(interstageBody, coreBody.getPreviousSymmetricComponent());
|
||||
assertEquals(podSetBody, insideBoosterBody.getPreviousSymmetricComponent());
|
||||
|
||||
// Case 6: inside booster is larger than pod set, pod set is before the back of the core stage, inside booster is an equal amount after the back of the pod set
|
||||
podSet.setAxialOffset(AxialMethod.BOTTOM, -1.5);
|
||||
insideBooster.setAxialOffset(AxialMethod.BOTTOM, 1.5);
|
||||
assertEquals(insideBoosterBody, lastStageBody.getPreviousSymmetricComponent());
|
||||
assertEquals(interstageBody, podSetCone.getPreviousSymmetricComponent());
|
||||
assertEquals(podSetCone, podSetBody.getPreviousSymmetricComponent());
|
||||
assertEquals(interstageBody, coreBody.getPreviousSymmetricComponent());
|
||||
assertEquals(podSetBody, insideBoosterBody.getPreviousSymmetricComponent());
|
||||
|
||||
// Case 7: inside booster is larger than pod set, pod set is after the back of the core stage, inside booster is an equal amount before the back of the pod set
|
||||
podSet.setAxialOffset(AxialMethod.BOTTOM, 1.5);
|
||||
insideBooster.setAxialOffset(AxialMethod.BOTTOM, -1.5);
|
||||
assertEquals(insideBoosterBody, lastStageBody.getPreviousSymmetricComponent());
|
||||
assertEquals(coreBody, podSetCone.getPreviousSymmetricComponent());
|
||||
assertEquals(podSetCone, podSetBody.getPreviousSymmetricComponent());
|
||||
assertEquals(interstageBody, coreBody.getPreviousSymmetricComponent());
|
||||
assertEquals(podSetCone, insideBoosterBody.getPreviousSymmetricComponent());
|
||||
|
||||
// Case 8: inside booster is larger than pod set, pod set is before the back of the core stage, inside booster is flush with the back of the pod set
|
||||
podSet.setAxialOffset(AxialMethod.BOTTOM, -1.5);
|
||||
insideBooster.setAxialOffset(AxialMethod.BOTTOM, 0);
|
||||
assertEquals(coreBody, lastStageBody.getPreviousSymmetricComponent());
|
||||
assertEquals(interstageBody, podSetCone.getPreviousSymmetricComponent());
|
||||
assertEquals(podSetCone, podSetBody.getPreviousSymmetricComponent());
|
||||
assertEquals(interstageBody, coreBody.getPreviousSymmetricComponent());
|
||||
assertEquals(podSetCone, insideBoosterBody.getPreviousSymmetricComponent());
|
||||
|
||||
// Case 9: inside booster is larger than pod set, pod set is after the back of the core stage, inside booster is flush with the back of the pod set
|
||||
podSet.setAxialOffset(AxialMethod.BOTTOM, 1.5);
|
||||
insideBooster.setAxialOffset(AxialMethod.BOTTOM, 0);
|
||||
assertEquals(coreBody, lastStageBody.getPreviousSymmetricComponent());
|
||||
assertEquals(coreBody, podSetCone.getPreviousSymmetricComponent());
|
||||
assertEquals(podSetCone, podSetBody.getPreviousSymmetricComponent());
|
||||
assertEquals(interstageBody, coreBody.getPreviousSymmetricComponent());
|
||||
assertEquals(podSetCone, insideBoosterBody.getPreviousSymmetricComponent());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testNextSymmetricComponent() {
|
||||
Rocket rocket = TestRockets.makeFalcon9Heavy();
|
||||
AxialStage payloadStage = rocket.getStage(0);
|
||||
NoseCone payloadFairingNoseCone = (NoseCone) payloadStage.getChild(0);
|
||||
BodyTube payloadBody = (BodyTube) payloadStage.getChild(1);
|
||||
Transition payloadFairingTail = (Transition) payloadStage.getChild(2);
|
||||
BodyTube upperStageBody = (BodyTube) payloadStage.getChild(3);
|
||||
BodyTube interstageBody = (BodyTube) payloadStage.getChild(4);
|
||||
|
||||
assertEquals(payloadBody, payloadFairingNoseCone.getNextSymmetricComponent());
|
||||
assertEquals(payloadFairingTail, payloadBody.getNextSymmetricComponent());
|
||||
assertEquals(upperStageBody, payloadFairingTail.getNextSymmetricComponent());
|
||||
assertEquals(interstageBody, upperStageBody.getNextSymmetricComponent());
|
||||
|
||||
AxialStage coreStage = rocket.getStage(1);
|
||||
BodyTube coreBody = (BodyTube) coreStage.getChild(0);
|
||||
|
||||
assertEquals(coreBody, interstageBody.getNextSymmetricComponent());
|
||||
assertNull(coreBody.getNextSymmetricComponent());
|
||||
|
||||
ParallelStage boosterStage = (ParallelStage) rocket.getStage(2);
|
||||
NoseCone boosterCone = (NoseCone) boosterStage.getChild(0);
|
||||
BodyTube boosterBody = (BodyTube) boosterStage.getChild(1);
|
||||
|
||||
assertEquals(boosterBody, boosterCone.getNextSymmetricComponent());
|
||||
assertNull(boosterBody.getNextSymmetricComponent());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testNextSymmetricComponentInlineComponentAssembly() {
|
||||
Rocket rocket = TestRockets.makeFalcon9Heavy();
|
||||
|
||||
// Stage 0
|
||||
AxialStage payloadStage = rocket.getStage(0);
|
||||
NoseCone payloadFairingNoseCone = (NoseCone) payloadStage.getChild(0);
|
||||
BodyTube payloadBody = (BodyTube) payloadStage.getChild(1);
|
||||
Transition payloadFairingTail = (Transition) payloadStage.getChild(2);
|
||||
BodyTube upperStageBody = (BodyTube) payloadStage.getChild(3);
|
||||
BodyTube interstageBody = (BodyTube) payloadStage.getChild(4);
|
||||
|
||||
// Stage 1
|
||||
AxialStage coreStage = rocket.getStage(1);
|
||||
BodyTube coreBody = (BodyTube) coreStage.getChild(0);
|
||||
|
||||
// Booster stage
|
||||
ParallelStage boosterStage = (ParallelStage) rocket.getStage(2);
|
||||
boosterStage.setInstanceCount(1);
|
||||
boosterStage.setRadius(RadiusMethod.RELATIVE, 0);
|
||||
NoseCone boosterCone = (NoseCone) boosterStage.getChild(0);
|
||||
BodyTube boosterBody = (BodyTube) boosterStage.getChild(1);
|
||||
|
||||
// Add inline pod set
|
||||
PodSet podSet = new PodSet();
|
||||
podSet.setName("Inline Pod Set");
|
||||
podSet.setInstanceCount(1);
|
||||
podSet.setRadius(RadiusMethod.FREE, 0);
|
||||
coreBody.addChild(podSet);
|
||||
podSet.setAxialOffset(AxialMethod.TOP, 0);
|
||||
BodyTube podSetBody = new BodyTube(0.2, 0.05, 0.001);
|
||||
podSetBody.setName("Pod Set Body");
|
||||
podSet.addChild(podSetBody);
|
||||
TrapezoidFinSet finSet = new TrapezoidFinSet();
|
||||
podSetBody.addChild(finSet);
|
||||
NoseCone podSetCone = new NoseCone();
|
||||
podSetCone.setLength(0.1);
|
||||
podSetCone.setBaseRadius(0.05);
|
||||
podSetCone.setFlipped(true);
|
||||
podSet.addChild(podSetCone);
|
||||
|
||||
// Add last stage
|
||||
AxialStage lastStage = new AxialStage();
|
||||
BodyTube lastStageBody = new BodyTube(0.2, 0.05, 0.001);
|
||||
lastStageBody.setName("Last Stage Body");
|
||||
lastStage.addChild(lastStageBody);
|
||||
rocket.addChild(lastStage);
|
||||
|
||||
assertEquals(payloadBody, payloadFairingNoseCone.getNextSymmetricComponent());
|
||||
assertEquals(payloadFairingTail, payloadBody.getNextSymmetricComponent());
|
||||
assertEquals(upperStageBody, payloadFairingTail.getNextSymmetricComponent());
|
||||
assertEquals(interstageBody, upperStageBody.getNextSymmetricComponent());
|
||||
|
||||
assertNull(lastStageBody.getNextSymmetricComponent());
|
||||
assertEquals(boosterBody, boosterCone.getNextSymmetricComponent());
|
||||
|
||||
// case 1: pod set is larger, and at the front of the core stage
|
||||
assertEquals(podSetBody, interstageBody.getNextSymmetricComponent());
|
||||
assertEquals(podSetCone, podSetBody.getNextSymmetricComponent());
|
||||
assertNull(podSetCone.getNextSymmetricComponent());
|
||||
assertEquals(lastStageBody, coreBody.getNextSymmetricComponent());
|
||||
|
||||
// case 2: pod set is smaller, and at the front of the core stage
|
||||
podSetBody.setOuterRadius(0.02);
|
||||
assertEquals(coreBody, interstageBody.getNextSymmetricComponent());
|
||||
assertEquals(podSetCone, podSetBody.getNextSymmetricComponent());
|
||||
assertNull(podSetCone.getNextSymmetricComponent());
|
||||
assertEquals(lastStageBody, coreBody.getNextSymmetricComponent());
|
||||
|
||||
// case 3: pod set is equal, and at the front of the core stage
|
||||
podSetBody.setOuterRadius(0.0385);
|
||||
assertEquals(coreBody, interstageBody.getNextSymmetricComponent());
|
||||
assertEquals(podSetCone, podSetBody.getNextSymmetricComponent());
|
||||
assertNull(podSetCone.getNextSymmetricComponent());
|
||||
assertEquals(lastStageBody, coreBody.getNextSymmetricComponent());
|
||||
|
||||
// case 4: pod set is larger, and at the back of the core stage
|
||||
podSetBody.setOuterRadius(0.05);
|
||||
podSet.setAxialOffset(AxialMethod.BOTTOM, 0);
|
||||
assertEquals(coreBody, interstageBody.getNextSymmetricComponent());
|
||||
assertEquals(podSetCone, podSetBody.getNextSymmetricComponent());
|
||||
assertNull(podSetCone.getNextSymmetricComponent());
|
||||
assertEquals(lastStageBody, coreBody.getNextSymmetricComponent());
|
||||
|
||||
// case 5: pod set is smaller, and at the back of the core stage
|
||||
podSetBody.setOuterRadius(0.02);
|
||||
assertEquals(coreBody, interstageBody.getNextSymmetricComponent());
|
||||
assertEquals(podSetCone, podSetBody.getNextSymmetricComponent());
|
||||
assertNull(podSetCone.getNextSymmetricComponent());
|
||||
assertEquals(lastStageBody, coreBody.getNextSymmetricComponent());
|
||||
|
||||
// case 6: pod set is equal, and at the back of the core stage
|
||||
podSetBody.setOuterRadius(0.0385);
|
||||
assertEquals(coreBody, interstageBody.getNextSymmetricComponent());
|
||||
assertEquals(podSetCone, podSetBody.getNextSymmetricComponent());
|
||||
assertNull(podSetCone.getNextSymmetricComponent());
|
||||
assertEquals(lastStageBody, coreBody.getNextSymmetricComponent());
|
||||
|
||||
// case 7: pod set is same length as core stage, and larger, and at the back of the core stage
|
||||
podSetBody.setOuterRadius(0.05);
|
||||
podSetBody.setLength(0.7);
|
||||
assertEquals(podSetBody, interstageBody.getNextSymmetricComponent());
|
||||
assertEquals(podSetCone, podSetBody.getNextSymmetricComponent());
|
||||
assertNull(podSetCone.getNextSymmetricComponent());
|
||||
assertEquals(lastStageBody, coreBody.getNextSymmetricComponent());
|
||||
|
||||
// case 8: pod set is same length as core stage, and smaller, and at the back of the core stage
|
||||
podSetBody.setOuterRadius(0.02);
|
||||
assertEquals(coreBody, interstageBody.getNextSymmetricComponent());
|
||||
assertEquals(podSetCone, podSetBody.getNextSymmetricComponent());
|
||||
assertNull(podSetCone.getNextSymmetricComponent());
|
||||
assertEquals(lastStageBody, coreBody.getNextSymmetricComponent());
|
||||
|
||||
// case 9: pod set is in larger, and in the middle of the core stage
|
||||
podSetBody.setLength(0.2);
|
||||
podSetBody.setOuterRadius(0.05);
|
||||
podSet.setAxialOffset(AxialMethod.MIDDLE, 0);
|
||||
assertEquals(coreBody, interstageBody.getNextSymmetricComponent());
|
||||
assertEquals(podSetCone, podSetBody.getNextSymmetricComponent());
|
||||
assertNull(podSetCone.getNextSymmetricComponent());
|
||||
assertEquals(lastStageBody, coreBody.getNextSymmetricComponent());
|
||||
|
||||
// case 10: pod set is in larger, and behind the front of the core stage
|
||||
podSet.setAxialOffset(AxialMethod.TOP, 1);
|
||||
assertEquals(coreBody, interstageBody.getNextSymmetricComponent());
|
||||
assertEquals(podSetCone, podSetBody.getNextSymmetricComponent());
|
||||
assertNull(podSetCone.getNextSymmetricComponent());
|
||||
assertEquals(lastStageBody, coreBody.getNextSymmetricComponent());
|
||||
|
||||
// Add a booster inside the pod set
|
||||
ParallelStage insideBooster = new ParallelStage();
|
||||
insideBooster.setName("Inside Booster");
|
||||
insideBooster.setInstanceCount(1);
|
||||
insideBooster.setRadius(RadiusMethod.FREE, 0);
|
||||
podSetBody.addChild(insideBooster);
|
||||
insideBooster.setAxialOffset(AxialMethod.TOP, 0);
|
||||
BodyTube insideBoosterBody = new BodyTube(0.2, 0.06, 0.001);
|
||||
insideBoosterBody.setName("Inside Booster Body");
|
||||
insideBooster.addChild(insideBoosterBody);
|
||||
|
||||
// Case 1: inside booster is larger than pod set and flush to its front (both are at the front of the core stage)
|
||||
podSet.setAxialOffset(AxialMethod.TOP, 0);
|
||||
insideBoosterBody.setOuterRadius(0.06);
|
||||
assertEquals(insideBoosterBody, interstageBody.getNextSymmetricComponent());
|
||||
assertEquals(podSetCone, podSetBody.getNextSymmetricComponent());
|
||||
assertNull(podSetCone.getNextSymmetricComponent());
|
||||
assertEquals(lastStageBody, coreBody.getNextSymmetricComponent());
|
||||
assertNull(insideBoosterBody.getNextSymmetricComponent());
|
||||
|
||||
// Case 2: inside booster is smaller than pod set and flush to its front
|
||||
insideBoosterBody.setOuterRadius(0.04);
|
||||
assertEquals(podSetBody, interstageBody.getNextSymmetricComponent());
|
||||
assertEquals(podSetCone, podSetBody.getNextSymmetricComponent());
|
||||
assertNull(podSetCone.getNextSymmetricComponent());
|
||||
assertEquals(lastStageBody, coreBody.getNextSymmetricComponent());
|
||||
assertNull(insideBoosterBody.getNextSymmetricComponent());
|
||||
|
||||
// Case 3: inside booster is equal the pod set and flush to its front
|
||||
insideBoosterBody.setOuterRadius(0.05);
|
||||
assertEquals(podSetBody, interstageBody.getNextSymmetricComponent());
|
||||
assertEquals(podSetCone, podSetBody.getNextSymmetricComponent());
|
||||
assertNull(podSetCone.getNextSymmetricComponent());
|
||||
assertEquals(lastStageBody, coreBody.getNextSymmetricComponent());
|
||||
assertNull(insideBoosterBody.getNextSymmetricComponent());
|
||||
|
||||
// Case 4: inside booster is larger than pod set and before the front (pod set at the front of the core stage)
|
||||
insideBooster.setAxialOffset(AxialMethod.TOP, -1);
|
||||
insideBoosterBody.setOuterRadius(0.06);
|
||||
assertEquals(podSetBody, interstageBody.getNextSymmetricComponent());
|
||||
assertEquals(podSetCone, podSetBody.getNextSymmetricComponent());
|
||||
assertNull(podSetCone.getNextSymmetricComponent());
|
||||
assertEquals(lastStageBody, coreBody.getNextSymmetricComponent());
|
||||
assertNull(insideBoosterBody.getNextSymmetricComponent());
|
||||
|
||||
// Case 5: inside booster is larger than pod set and after the front (pod set at the front of the core stage)
|
||||
insideBooster.setAxialOffset(AxialMethod.TOP, 1);
|
||||
assertEquals(podSetBody, interstageBody.getNextSymmetricComponent());
|
||||
assertEquals(podSetCone, podSetBody.getNextSymmetricComponent());
|
||||
assertNull(podSetCone.getNextSymmetricComponent());
|
||||
assertEquals(lastStageBody, coreBody.getNextSymmetricComponent());
|
||||
assertNull(insideBoosterBody.getNextSymmetricComponent());
|
||||
|
||||
// Case 6: inside booster is larger than pod set, pod set is before the front of the core stage, inside booster is an equal amount after the front of the pod set
|
||||
podSet.setAxialOffset(AxialMethod.TOP, -1.5);
|
||||
insideBooster.setAxialOffset(AxialMethod.TOP, 1.5);
|
||||
assertEquals(insideBoosterBody, interstageBody.getNextSymmetricComponent());
|
||||
assertEquals(podSetCone, podSetBody.getNextSymmetricComponent());
|
||||
assertNull(podSetCone.getNextSymmetricComponent());
|
||||
assertEquals(lastStageBody, coreBody.getNextSymmetricComponent());
|
||||
assertNull(insideBoosterBody.getNextSymmetricComponent());
|
||||
|
||||
// Case 7: inside booster is larger than pod set, pod set is after the front of the core stage, inside booster is an equal amount before the front of the pod set
|
||||
podSet.setAxialOffset(AxialMethod.TOP, 1.5);
|
||||
insideBooster.setAxialOffset(AxialMethod.TOP, -1.5);
|
||||
assertEquals(insideBoosterBody, interstageBody.getNextSymmetricComponent());
|
||||
assertEquals(podSetCone, podSetBody.getNextSymmetricComponent());
|
||||
assertNull(podSetCone.getNextSymmetricComponent());
|
||||
assertEquals(lastStageBody, coreBody.getNextSymmetricComponent());
|
||||
assertNull(insideBoosterBody.getNextSymmetricComponent());
|
||||
|
||||
// Case 8: inside booster is larger than pod set, pod set is before the front of the core stage, inside booster is flush with the front of the pod set
|
||||
podSet.setAxialOffset(AxialMethod.TOP, -1.5);
|
||||
insideBooster.setAxialOffset(AxialMethod.TOP, 0);
|
||||
assertEquals(coreBody, interstageBody.getNextSymmetricComponent());
|
||||
assertEquals(podSetCone, podSetBody.getNextSymmetricComponent());
|
||||
assertNull(podSetCone.getNextSymmetricComponent());
|
||||
assertEquals(lastStageBody, coreBody.getNextSymmetricComponent());
|
||||
assertNull(insideBoosterBody.getNextSymmetricComponent());
|
||||
|
||||
// Case 9: inside booster is larger than pod set, pod set is after the front of the core stage, inside booster is flush with the front of the pod set
|
||||
podSet.setAxialOffset(AxialMethod.TOP, 1.5);
|
||||
insideBooster.setAxialOffset(AxialMethod.TOP, 0);
|
||||
assertEquals(coreBody, interstageBody.getNextSymmetricComponent());
|
||||
assertEquals(podSetCone, podSetBody.getNextSymmetricComponent());
|
||||
assertNull(podSetCone.getNextSymmetricComponent());
|
||||
assertEquals(lastStageBody, coreBody.getNextSymmetricComponent());
|
||||
assertNull(insideBoosterBody.getNextSymmetricComponent());
|
||||
}
|
||||
}
|
@ -8,443 +8,380 @@ import net.sf.openrocket.util.BaseTestCase.BaseTestCase;
|
||||
import org.junit.Test;
|
||||
|
||||
public class SymmetricComponentVolumeTest extends BaseTestCase {
|
||||
|
||||
@Test
|
||||
public void simpleConeFilled() {
|
||||
NoseCone nc = new NoseCone();
|
||||
|
||||
final double epsilonPercent = 0.001;
|
||||
final double density = 2.0;
|
||||
|
||||
nc.setLength(1.0);
|
||||
nc.setFilled(true);
|
||||
nc.setType(Transition.Shape.CONICAL);
|
||||
nc.setAftRadius(1.0);
|
||||
nc.setMaterial(Material.newMaterial(Material.Type.BULK, "test", density, true));
|
||||
|
||||
Coordinate cg = nc.getCG();
|
||||
|
||||
//System.out.println(nc.getComponentVolume() + "\t" + nc.getMass());
|
||||
//System.out.println(cg);
|
||||
|
||||
double volume = Math.PI / 3.0;
|
||||
|
||||
double mass = density * volume;
|
||||
|
||||
//System.out.println(volume);
|
||||
|
||||
assertEquals(volume, nc.getComponentVolume(), epsilonPercent * volume);
|
||||
assertEquals(mass, nc.getMass(), epsilonPercent * mass);
|
||||
|
||||
assertEquals(0.75, cg.x, epsilonPercent * 0.75);
|
||||
assertEquals(mass, cg.weight, epsilonPercent * mass);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void simpleConeWithShoulderFilled() {
|
||||
NoseCone nc = new NoseCone();
|
||||
|
||||
final double epsilonPercent = 0.001;
|
||||
final double density = 2.0;
|
||||
|
||||
nc.setLength(1.0);
|
||||
nc.setFilled(true);
|
||||
nc.setType(Transition.Shape.CONICAL);
|
||||
nc.setAftRadius(1.0);
|
||||
nc.setAftShoulderRadius(1.0);
|
||||
nc.setAftShoulderLength(1.0);
|
||||
nc.setAftShoulderThickness(1.0);
|
||||
nc.setMaterial(Material.newMaterial(Material.Type.BULK, "test", density, true));
|
||||
|
||||
Coordinate cg = nc.getCG();
|
||||
|
||||
//System.out.println(nc.getComponentVolume() + "\t" + nc.getMass());
|
||||
//System.out.println(cg);
|
||||
|
||||
double volume = Math.PI / 3.0;
|
||||
volume += Math.PI;
|
||||
|
||||
double mass = density * volume;
|
||||
|
||||
//System.out.println(volume + "\t" + mass);
|
||||
|
||||
assertEquals(volume, nc.getComponentVolume(), epsilonPercent * volume);
|
||||
assertEquals(mass, nc.getMass(), epsilonPercent * mass);
|
||||
|
||||
assertEquals(1.312, cg.x, epsilonPercent * 1.071);
|
||||
assertEquals(mass, cg.weight, epsilonPercent * mass);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void simpleConeHollow() {
|
||||
NoseCone nc = new NoseCone();
|
||||
|
||||
final double epsilonPercent = 0.001;
|
||||
final double density = 2.0;
|
||||
|
||||
nc.setLength(1.0);
|
||||
nc.setAftRadius(1.0);
|
||||
nc.setThickness(0.5);
|
||||
nc.setType(Transition.Shape.CONICAL);
|
||||
nc.setMaterial(Material.newMaterial(Material.Type.BULK, "test", density, true));
|
||||
|
||||
Coordinate cg = nc.getCG();
|
||||
|
||||
//System.out.println(nc.getComponentVolume() + "\t" + nc.getMass());
|
||||
//System.out.println(cg);
|
||||
|
||||
double volume = Math.PI / 3.0; // outer volume
|
||||
|
||||
// manually projected Thickness of 0.5 on to radius to determine
|
||||
// the innerConeDimen. Since the outer cone is "square" (height = radius),
|
||||
// we only need to compute this one dimension in order to compute the
|
||||
// volume of the inner cone.
|
||||
double innerConeDimen = 1.0 - Math.sqrt(2.0) / 2.0;
|
||||
double innerVolume = Math.PI / 3.0 * innerConeDimen * innerConeDimen * innerConeDimen;
|
||||
volume -= innerVolume;
|
||||
|
||||
double mass = density * volume;
|
||||
|
||||
//System.out.println(volume);
|
||||
|
||||
assertEquals(volume, nc.getComponentVolume(), epsilonPercent * volume);
|
||||
assertEquals(mass, nc.getMass(), epsilonPercent * mass);
|
||||
|
||||
assertEquals(0.7454, cg.x, epsilonPercent * 0.7454);
|
||||
assertEquals(mass, cg.weight, epsilonPercent * mass);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void simpleConeWithShoulderHollow() {
|
||||
NoseCone nc = new NoseCone();
|
||||
|
||||
final double epsilonPercent = 0.001;
|
||||
final double density = 2.0;
|
||||
|
||||
nc.setLength(1.0);
|
||||
nc.setType(Transition.Shape.CONICAL);
|
||||
nc.setAftRadius(1.0);
|
||||
nc.setThickness(0.5);
|
||||
nc.setAftShoulderRadius(1.0);
|
||||
nc.setAftShoulderLength(1.0);
|
||||
nc.setAftShoulderThickness(0.5);
|
||||
nc.setMaterial(Material.newMaterial(Material.Type.BULK, "test", density, true));
|
||||
|
||||
Coordinate cg = nc.getCG();
|
||||
|
||||
//System.out.println(nc.getComponentVolume() + "\t" + nc.getMass());
|
||||
//System.out.println(cg);
|
||||
|
||||
double volume = Math.PI / 3.0; // outer volume
|
||||
|
||||
// manually projected Thickness of 0.5 on to radius to determine
|
||||
// the innerConeDimen. Since the outer cone is "square" (height = radius),
|
||||
// we only need to compute this one dimension in order to compute the
|
||||
// volume of the inner cone.
|
||||
double innerConeDimen = 1.0 - Math.sqrt(2.0) / 2.0;
|
||||
double innerVolume = Math.PI / 3.0 * innerConeDimen * innerConeDimen * innerConeDimen;
|
||||
volume -= innerVolume;
|
||||
|
||||
volume += Math.PI - Math.PI * 0.5 * 0.5;
|
||||
|
||||
|
||||
double mass = density * volume;
|
||||
|
||||
//System.out.println(volume);
|
||||
|
||||
assertEquals(volume, nc.getComponentVolume(), epsilonPercent * volume);
|
||||
assertEquals(mass, nc.getMass(), epsilonPercent * mass);
|
||||
|
||||
assertEquals(1.2719, cg.x, epsilonPercent * 1.2719);
|
||||
assertEquals(mass, cg.weight, epsilonPercent * mass);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void simpleTransitionFilled() {
|
||||
Transition nc = new Transition();
|
||||
|
||||
final double epsilonPercent = 0.001;
|
||||
final double density = 2.0;
|
||||
|
||||
nc.setLength(4.0);
|
||||
nc.setFilled(true);
|
||||
nc.setType(Transition.Shape.CONICAL);
|
||||
nc.setForeRadius(1.0);
|
||||
nc.setAftRadius(2.0);
|
||||
nc.setMaterial(Material.newMaterial(Material.Type.BULK, "test", density, true));
|
||||
|
||||
Coordinate cg = nc.getCG();
|
||||
|
||||
//System.out.println(nc.getComponentVolume() + "\t" + nc.getMass());
|
||||
//System.out.println(cg);
|
||||
|
||||
double volume = Math.PI / 3.0 * (2.0 * 2.0 + 2.0 * 1.0 + 1.0 * 1.0) * 4.0;
|
||||
|
||||
double mass = density * volume;
|
||||
|
||||
//System.out.println(volume);
|
||||
|
||||
assertEquals(volume, nc.getComponentVolume(), epsilonPercent * volume);
|
||||
assertEquals(mass, nc.getMass(), epsilonPercent * mass);
|
||||
|
||||
assertEquals(2.4285, cg.x, epsilonPercent * 2.4285);
|
||||
assertEquals(mass, cg.weight, epsilonPercent * mass);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void simpleTransitionWithShouldersFilled() {
|
||||
Transition nc = new Transition();
|
||||
|
||||
final double epsilonPercent = 0.001;
|
||||
final double density = 2.0;
|
||||
|
||||
nc.setLength(4.0);
|
||||
nc.setFilled(true);
|
||||
nc.setType(Transition.Shape.CONICAL);
|
||||
nc.setForeRadius(1.0);
|
||||
nc.setAftRadius(2.0);
|
||||
nc.setAftShoulderLength(1.0);
|
||||
nc.setAftShoulderRadius(2.0);
|
||||
nc.setAftShoulderThickness(2.0);
|
||||
nc.setForeShoulderLength(1.0);
|
||||
nc.setForeShoulderRadius(1.0);
|
||||
nc.setForeShoulderThickness(1.0);
|
||||
nc.setMaterial(Material.newMaterial(Material.Type.BULK, "test", density, true));
|
||||
|
||||
Coordinate cg = nc.getCG();
|
||||
|
||||
//System.out.println(nc.getComponentVolume() + "\t" + nc.getMass());
|
||||
//System.out.println(cg);
|
||||
|
||||
double volume = Math.PI / 3.0 * (2.0 * 2.0 + 2.0 * 1.0 + 1.0 * 1.0) * 4.0;
|
||||
// plus aft shoulder:
|
||||
volume += Math.PI * 1.0 * 2.0 * 2.0;
|
||||
// plus fore shoulder:
|
||||
volume += Math.PI * 1.0 * 1.0 * 1.0;
|
||||
|
||||
double mass = density * volume;
|
||||
|
||||
//System.out.println(volume);
|
||||
|
||||
assertEquals(volume, nc.getComponentVolume(), epsilonPercent * volume);
|
||||
assertEquals(mass, nc.getMass(), epsilonPercent * mass);
|
||||
|
||||
assertEquals(2.8023, cg.x, epsilonPercent * 2.8023);
|
||||
assertEquals(mass, cg.weight, epsilonPercent * mass);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void simpleTransitionHollow1() {
|
||||
Transition nc = new Transition();
|
||||
|
||||
final double epsilonPercent = 0.001;
|
||||
final double density = 2.0;
|
||||
|
||||
nc.setLength(1.0);
|
||||
nc.setType(Transition.Shape.CONICAL);
|
||||
nc.setForeRadius(0.5);
|
||||
nc.setAftRadius(1.0);
|
||||
nc.setThickness(0.5);
|
||||
nc.setMaterial(Material.newMaterial(Material.Type.BULK, "test", density, true));
|
||||
|
||||
Coordinate cg = nc.getCG();
|
||||
|
||||
//System.out.println(nc.getComponentVolume() + "\t" + nc.getMass());
|
||||
//System.out.println(cg);
|
||||
|
||||
// Volume of filled transition =
|
||||
double filledVolume = Math.PI / 3.0 * (1.0 * 1.0 + 1.0 * 0.5 + 0.5 * 0.5) * 1.0;
|
||||
|
||||
// magic 2D cad drawing...
|
||||
//
|
||||
// Since the thickness >= fore radius, the
|
||||
// hollowed out portion of the transition
|
||||
// forms a cone.
|
||||
// the dimensions of this cone were determined
|
||||
// using a 2d cad tool.
|
||||
|
||||
double innerConeRadius = 0.441;
|
||||
double innerConeLength = 0.882;
|
||||
double innerVolume = Math.PI / 3.0 * innerConeLength * innerConeRadius * innerConeRadius;
|
||||
|
||||
double volume = filledVolume - innerVolume;
|
||||
|
||||
double mass = density * volume;
|
||||
|
||||
//System.out.println(volume);
|
||||
|
||||
assertEquals(volume, nc.getComponentVolume(), epsilonPercent * volume);
|
||||
assertEquals(mass, nc.getMass(), epsilonPercent * mass);
|
||||
|
||||
assertEquals(0.5884, cg.x, epsilonPercent * 0.5884);
|
||||
assertEquals(mass, cg.weight, epsilonPercent * mass);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void simpleTransitionWithShouldersHollow1() {
|
||||
Transition nc = new Transition();
|
||||
|
||||
final double epsilonPercent = 0.001;
|
||||
final double density = 2.0;
|
||||
|
||||
nc.setLength(1.0);
|
||||
nc.setType(Transition.Shape.CONICAL);
|
||||
nc.setForeRadius(0.5);
|
||||
nc.setAftRadius(1.0);
|
||||
nc.setThickness(0.5);
|
||||
nc.setAftShoulderLength(1.0);
|
||||
nc.setAftShoulderRadius(1.0);
|
||||
nc.setAftShoulderThickness(0.5);
|
||||
nc.setForeShoulderLength(1.0);
|
||||
nc.setForeShoulderRadius(0.5);
|
||||
nc.setForeShoulderThickness(0.5); // note this means fore shoulder is filled.
|
||||
nc.setMaterial(Material.newMaterial(Material.Type.BULK, "test", density, true));
|
||||
|
||||
Coordinate cg = nc.getCG();
|
||||
|
||||
//System.out.println(nc.getComponentVolume() + "\t" + nc.getMass());
|
||||
//System.out.println(cg);
|
||||
|
||||
// Volume of filled transition =
|
||||
double filledVolume = Math.PI / 3.0 * (1.0 * 1.0 + 1.0 * 0.5 + 0.5 * 0.5) * 1.0;
|
||||
|
||||
// magic 2D cad drawing...
|
||||
//
|
||||
// Since the thickness >= fore radius, the
|
||||
// hollowed out portion of the transition
|
||||
// forms a cone.
|
||||
// the dimensions of this cone were determined
|
||||
// using a 2d cad tool.
|
||||
|
||||
double innerConeRadius = 0.441;
|
||||
double innerConeLength = 0.882;
|
||||
double innerVolume = Math.PI / 3.0 * innerConeLength * innerConeRadius * innerConeRadius;
|
||||
|
||||
double volume = filledVolume - innerVolume;
|
||||
|
||||
// Now add aft shoulder
|
||||
volume += Math.PI * 1.0 * 1.0 * 1.0 - Math.PI * 1.0 * 0.5 * 0.5;
|
||||
// Now add fore shoulder
|
||||
volume += Math.PI * 1.0 * 0.5 * 0.5;
|
||||
|
||||
double mass = density * volume;
|
||||
|
||||
//System.out.println(volume);
|
||||
|
||||
assertEquals(volume, nc.getComponentVolume(), epsilonPercent * volume);
|
||||
assertEquals(mass, nc.getMass(), epsilonPercent * mass);
|
||||
|
||||
assertEquals(0.8581, cg.x, epsilonPercent * 0.8581);
|
||||
assertEquals(mass, cg.weight, epsilonPercent * mass);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void simpleTransitionHollow2() {
|
||||
Transition nc = new Transition();
|
||||
|
||||
final double epsilonPercent = 0.001;
|
||||
final double density = 2.0;
|
||||
|
||||
nc.setLength(1.0);
|
||||
nc.setType(Transition.Shape.CONICAL);
|
||||
nc.setForeRadius(0.5);
|
||||
nc.setAftRadius(1.0);
|
||||
nc.setThickness(0.25);
|
||||
nc.setMaterial(Material.newMaterial(Material.Type.BULK, "test", density, true));
|
||||
|
||||
Coordinate cg = nc.getCG();
|
||||
|
||||
//System.out.println(nc.getComponentVolume() + "\t" + nc.getMass());
|
||||
//System.out.println(cg);
|
||||
|
||||
// Volume of filled transition =
|
||||
double filledVolume = Math.PI / 3.0 * (1.0 * 1.0 + 1.0 * 0.5 + 0.5 * 0.5) * 1.0;
|
||||
|
||||
// magic 2D cad drawing...
|
||||
//
|
||||
// Since the thickness < fore radius, the
|
||||
// hollowed out portion of the transition
|
||||
// forms a transition.
|
||||
// the dimensions of this transition were determined
|
||||
// using a 2d cad tool.
|
||||
|
||||
double innerTransitionAftRadius = 0.7205;
|
||||
double innerTransitionForeRadius = 0.2205;
|
||||
double innerVolume = Math.PI / 3.0
|
||||
* (innerTransitionAftRadius * innerTransitionAftRadius + innerTransitionAftRadius * innerTransitionForeRadius + innerTransitionForeRadius * innerTransitionForeRadius);
|
||||
|
||||
double volume = filledVolume - innerVolume;
|
||||
|
||||
double mass = density * volume;
|
||||
|
||||
//System.out.println(volume);
|
||||
|
||||
assertEquals(volume, nc.getComponentVolume(), epsilonPercent * volume);
|
||||
assertEquals(mass, nc.getMass(), epsilonPercent * mass);
|
||||
|
||||
assertEquals(0.56827, cg.x, epsilonPercent * 0.56827);
|
||||
assertEquals(mass, cg.weight, epsilonPercent * mass);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void simpleTransitionWithShouldersHollow2() {
|
||||
Transition nc = new Transition();
|
||||
|
||||
final double epsilonPercent = 0.001;
|
||||
final double density = 2.0;
|
||||
|
||||
nc.setLength(1.0);
|
||||
nc.setType(Transition.Shape.CONICAL);
|
||||
nc.setForeRadius(0.5);
|
||||
nc.setAftRadius(1.0);
|
||||
nc.setThickness(0.25);
|
||||
nc.setAftShoulderLength(1.0);
|
||||
nc.setAftShoulderRadius(1.0);
|
||||
nc.setAftShoulderThickness(0.25);
|
||||
nc.setForeShoulderLength(1.0);
|
||||
nc.setForeShoulderRadius(0.5);
|
||||
nc.setForeShoulderThickness(0.25);
|
||||
|
||||
nc.setMaterial(Material.newMaterial(Material.Type.BULK, "test", density, true));
|
||||
|
||||
Coordinate cg = nc.getCG();
|
||||
|
||||
//System.out.println(nc.getComponentVolume() + "\t" + nc.getMass());
|
||||
//System.out.println(cg);
|
||||
|
||||
// Volume of filled transition =
|
||||
double filledVolume = Math.PI / 3.0 * (1.0 * 1.0 + 1.0 * 0.5 + 0.5 * 0.5) * 1.0;
|
||||
|
||||
// magic 2D cad drawing...
|
||||
//
|
||||
// Since the thickness < fore radius, the
|
||||
// hollowed out portion of the transition
|
||||
// forms a transition.
|
||||
// the dimensions of this transition were determined
|
||||
// using a 2d cad tool.
|
||||
|
||||
double innerTransitionAftRadius = 0.7205;
|
||||
double innerTransitionForeRadius = 0.2205;
|
||||
double innerVolume = Math.PI / 3.0
|
||||
* (innerTransitionAftRadius * innerTransitionAftRadius + innerTransitionAftRadius * innerTransitionForeRadius + innerTransitionForeRadius * innerTransitionForeRadius);
|
||||
|
||||
double volume = filledVolume - innerVolume;
|
||||
|
||||
// now add aft shoulder
|
||||
volume += Math.PI * 1.0 * 1.0 * 1.0 - Math.PI * 1.0 * 0.75 * 0.75;
|
||||
// now add fore shoulder
|
||||
volume += Math.PI * 1.0 * 0.5 * 0.5 - Math.PI * 1.0 * 0.25 * 0.25;
|
||||
|
||||
|
||||
double mass = density * volume;
|
||||
|
||||
//System.out.println(volume);
|
||||
|
||||
assertEquals(volume, nc.getComponentVolume(), epsilonPercent * volume);
|
||||
assertEquals(mass, nc.getMass(), epsilonPercent * mass);
|
||||
|
||||
assertEquals(0.7829, cg.x, epsilonPercent * 0.7829);
|
||||
assertEquals(mass, cg.weight, epsilonPercent * mass);
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void testVolumeSimpleConeFilled() {
|
||||
NoseCone nc = new NoseCone();
|
||||
|
||||
final double epsilonPercent = 0.001;
|
||||
final double density = 2.0;
|
||||
|
||||
nc.setLength(1.0);
|
||||
nc.setFilled(true);
|
||||
nc.setType(Transition.Shape.CONICAL);
|
||||
nc.setAftRadius(1.0);
|
||||
nc.setMaterial(Material.newMaterial(Material.Type.BULK, "test", density, true));
|
||||
|
||||
Coordinate cg = nc.getCG();
|
||||
double volume = Math.PI / 3.0;
|
||||
double mass = density * volume;
|
||||
|
||||
assertEquals(volume, nc.getComponentVolume(), epsilonPercent * volume);
|
||||
assertEquals(mass, nc.getMass(), epsilonPercent * mass);
|
||||
|
||||
assertEquals(0.75, cg.x, epsilonPercent * 0.75);
|
||||
assertEquals(mass, cg.weight, epsilonPercent * mass);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testVolumeSimpleConeWithShoulderFilled() {
|
||||
NoseCone nc = new NoseCone();
|
||||
|
||||
final double epsilonPercent = 0.001;
|
||||
final double density = 2.0;
|
||||
|
||||
nc.setLength(1.0);
|
||||
nc.setFilled(true);
|
||||
nc.setType(Transition.Shape.CONICAL);
|
||||
nc.setAftRadius(1.0);
|
||||
nc.setAftShoulderRadius(1.0);
|
||||
nc.setAftShoulderLength(1.0);
|
||||
nc.setAftShoulderThickness(1.0);
|
||||
nc.setMaterial(Material.newMaterial(Material.Type.BULK, "test", density, true));
|
||||
|
||||
Coordinate cg = nc.getCG();
|
||||
|
||||
double volume = Math.PI / 3.0;
|
||||
volume += Math.PI;
|
||||
double mass = density * volume;
|
||||
|
||||
assertEquals(volume, nc.getComponentVolume(), epsilonPercent * volume);
|
||||
assertEquals(mass, nc.getMass(), epsilonPercent * mass);
|
||||
|
||||
assertEquals(1.312, cg.x, epsilonPercent * 1.071);
|
||||
assertEquals(mass, cg.weight, epsilonPercent * mass);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testVolumeSimpleConeHollow() {
|
||||
NoseCone nc = new NoseCone();
|
||||
|
||||
final double epsilonPercent = 0.001;
|
||||
final double density = 2.0;
|
||||
|
||||
nc.setLength(1.0);
|
||||
nc.setAftRadius(1.0);
|
||||
nc.setThickness(0.5);
|
||||
nc.setType(Transition.Shape.CONICAL);
|
||||
nc.setMaterial(Material.newMaterial(Material.Type.BULK, "test", density, true));
|
||||
|
||||
Coordinate cg = nc.getCG();
|
||||
|
||||
double volume = Math.PI / 3.0; // outer volume
|
||||
|
||||
// manually projected Thickness of 0.5 on to radius to determine
|
||||
// the innerConeDimen. Since the outer cone is "square" (height = radius),
|
||||
// we only need to compute this one dimension in order to compute the
|
||||
// volume of the inner cone.
|
||||
double innerConeDimen = 1.0 - Math.sqrt(2.0) / 2.0;
|
||||
double innerVolume = Math.PI / 3.0 * innerConeDimen * innerConeDimen * innerConeDimen;
|
||||
volume -= innerVolume;
|
||||
|
||||
double mass = density * volume;
|
||||
|
||||
assertEquals(volume, nc.getComponentVolume(), epsilonPercent * volume);
|
||||
assertEquals(mass, nc.getMass(), epsilonPercent * mass);
|
||||
|
||||
assertEquals(0.7454, cg.x, epsilonPercent * 0.7454);
|
||||
assertEquals(mass, cg.weight, epsilonPercent * mass);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testVolumeSimpleConeWithShoulderHollow() {
|
||||
NoseCone nc = new NoseCone();
|
||||
|
||||
final double epsilonPercent = 0.001;
|
||||
final double density = 2.0;
|
||||
|
||||
nc.setLength(1.0);
|
||||
nc.setType(Transition.Shape.CONICAL);
|
||||
nc.setAftRadius(1.0);
|
||||
nc.setThickness(0.5);
|
||||
nc.setAftShoulderRadius(1.0);
|
||||
nc.setAftShoulderLength(1.0);
|
||||
nc.setAftShoulderThickness(0.5);
|
||||
nc.setMaterial(Material.newMaterial(Material.Type.BULK, "test", density, true));
|
||||
|
||||
Coordinate cg = nc.getCG();
|
||||
|
||||
double volume = Math.PI / 3.0; // outer volume
|
||||
|
||||
// manually projected Thickness of 0.5 on to radius to determine
|
||||
// the innerConeDimen. Since the outer cone is "square" (height = radius),
|
||||
// we only need to compute this one dimension in order to compute the
|
||||
// volume of the inner cone.
|
||||
double innerConeDimen = 1.0 - Math.sqrt(2.0) / 2.0;
|
||||
double innerVolume = Math.PI / 3.0 * innerConeDimen * innerConeDimen * innerConeDimen;
|
||||
volume -= innerVolume;
|
||||
volume += Math.PI - Math.PI * 0.5 * 0.5;
|
||||
double mass = density * volume;
|
||||
|
||||
assertEquals(volume, nc.getComponentVolume(), epsilonPercent * volume);
|
||||
assertEquals(mass, nc.getMass(), epsilonPercent * mass);
|
||||
|
||||
assertEquals(1.2719, cg.x, epsilonPercent * 1.2719);
|
||||
assertEquals(mass, cg.weight, epsilonPercent * mass);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testVolumeSimpleTransitionFilled() {
|
||||
Transition nc = new Transition();
|
||||
|
||||
final double epsilonPercent = 0.001;
|
||||
final double density = 2.0;
|
||||
|
||||
nc.setLength(4.0);
|
||||
nc.setFilled(true);
|
||||
nc.setType(Transition.Shape.CONICAL);
|
||||
nc.setForeRadius(1.0);
|
||||
nc.setAftRadius(2.0);
|
||||
nc.setMaterial(Material.newMaterial(Material.Type.BULK, "test", density, true));
|
||||
|
||||
Coordinate cg = nc.getCG();
|
||||
double volume = Math.PI / 3.0 * (2.0 * 2.0 + 2.0 * 1.0 + 1.0 * 1.0) * 4.0;
|
||||
double mass = density * volume;
|
||||
|
||||
assertEquals(volume, nc.getComponentVolume(), epsilonPercent * volume);
|
||||
assertEquals(mass, nc.getMass(), epsilonPercent * mass);
|
||||
|
||||
assertEquals(2.4285, cg.x, epsilonPercent * 2.4285);
|
||||
assertEquals(mass, cg.weight, epsilonPercent * mass);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testVolumeSimpleTransitionWithShouldersFilled() {
|
||||
Transition nc = new Transition();
|
||||
|
||||
final double epsilonPercent = 0.001;
|
||||
final double density = 2.0;
|
||||
|
||||
nc.setLength(4.0);
|
||||
nc.setFilled(true);
|
||||
nc.setType(Transition.Shape.CONICAL);
|
||||
nc.setForeRadius(1.0);
|
||||
nc.setAftRadius(2.0);
|
||||
nc.setAftShoulderLength(1.0);
|
||||
nc.setAftShoulderRadius(2.0);
|
||||
nc.setAftShoulderThickness(2.0);
|
||||
nc.setForeShoulderLength(1.0);
|
||||
nc.setForeShoulderRadius(1.0);
|
||||
nc.setForeShoulderThickness(1.0);
|
||||
nc.setMaterial(Material.newMaterial(Material.Type.BULK, "test", density, true));
|
||||
|
||||
Coordinate cg = nc.getCG();
|
||||
|
||||
double volume = Math.PI / 3.0 * (2.0 * 2.0 + 2.0 * 1.0 + 1.0 * 1.0) * 4.0;
|
||||
// plus aft shoulder:
|
||||
volume += Math.PI * 1.0 * 2.0 * 2.0;
|
||||
// plus fore shoulder:
|
||||
volume += Math.PI * 1.0 * 1.0 * 1.0;
|
||||
double mass = density * volume;
|
||||
|
||||
assertEquals(volume, nc.getComponentVolume(), epsilonPercent * volume);
|
||||
assertEquals(mass, nc.getMass(), epsilonPercent * mass);
|
||||
|
||||
assertEquals(2.8023, cg.x, epsilonPercent * 2.8023);
|
||||
assertEquals(mass, cg.weight, epsilonPercent * mass);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testVolumeSimpleTransitionHollow1() {
|
||||
Transition nc = new Transition();
|
||||
|
||||
final double epsilonPercent = 0.001;
|
||||
final double density = 2.0;
|
||||
|
||||
nc.setLength(1.0);
|
||||
nc.setType(Transition.Shape.CONICAL);
|
||||
nc.setForeRadius(0.5);
|
||||
nc.setAftRadius(1.0);
|
||||
nc.setThickness(0.5);
|
||||
nc.setMaterial(Material.newMaterial(Material.Type.BULK, "test", density, true));
|
||||
|
||||
Coordinate cg = nc.getCG();
|
||||
|
||||
// Volume of filled transition =
|
||||
double filledVolume = Math.PI / 3.0 * (1.0 * 1.0 + 1.0 * 0.5 + 0.5 * 0.5) * 1.0;
|
||||
|
||||
// magic 2D cad drawing...
|
||||
//
|
||||
// Since the thickness >= fore radius, the
|
||||
// hollowed out portion of the transition
|
||||
// forms a cone.
|
||||
// the dimensions of this cone were determined
|
||||
// using a 2d cad tool.
|
||||
|
||||
double innerConeRadius = 0.441;
|
||||
double innerConeLength = 0.882;
|
||||
double innerVolume = Math.PI / 3.0 * innerConeLength * innerConeRadius * innerConeRadius;
|
||||
double volume = filledVolume - innerVolume;
|
||||
double mass = density * volume;
|
||||
|
||||
assertEquals(volume, nc.getComponentVolume(), epsilonPercent * volume);
|
||||
assertEquals(mass, nc.getMass(), epsilonPercent * mass);
|
||||
|
||||
assertEquals(0.5884, cg.x, epsilonPercent * 0.5884);
|
||||
assertEquals(mass, cg.weight, epsilonPercent * mass);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testVolumeSimpleTransitionWithShouldersHollow1() {
|
||||
Transition nc = new Transition();
|
||||
|
||||
final double epsilonPercent = 0.001;
|
||||
final double density = 2.0;
|
||||
|
||||
nc.setLength(1.0);
|
||||
nc.setType(Transition.Shape.CONICAL);
|
||||
nc.setForeRadius(0.5);
|
||||
nc.setAftRadius(1.0);
|
||||
nc.setThickness(0.5);
|
||||
nc.setAftShoulderLength(1.0);
|
||||
nc.setAftShoulderRadius(1.0);
|
||||
nc.setAftShoulderThickness(0.5);
|
||||
nc.setForeShoulderLength(1.0);
|
||||
nc.setForeShoulderRadius(0.5);
|
||||
nc.setForeShoulderThickness(0.5); // note this means fore shoulder is filled.
|
||||
nc.setMaterial(Material.newMaterial(Material.Type.BULK, "test", density, true));
|
||||
|
||||
Coordinate cg = nc.getCG();
|
||||
|
||||
// Volume of filled transition =
|
||||
double filledVolume = Math.PI / 3.0 * (1.0 * 1.0 + 1.0 * 0.5 + 0.5 * 0.5) * 1.0;
|
||||
|
||||
// magic 2D cad drawing...
|
||||
//
|
||||
// Since the thickness >= fore radius, the
|
||||
// hollowed out portion of the transition
|
||||
// forms a cone.
|
||||
// the dimensions of this cone were determined
|
||||
// using a 2d cad tool.
|
||||
|
||||
double innerConeRadius = 0.441;
|
||||
double innerConeLength = 0.882;
|
||||
double innerVolume = Math.PI / 3.0 * innerConeLength * innerConeRadius * innerConeRadius;
|
||||
|
||||
double volume = filledVolume - innerVolume;
|
||||
|
||||
// Now add aft shoulder
|
||||
volume += Math.PI * 1.0 * 1.0 * 1.0 - Math.PI * 1.0 * 0.5 * 0.5;
|
||||
// Now add fore shoulder
|
||||
volume += Math.PI * 1.0 * 0.5 * 0.5;
|
||||
|
||||
double mass = density * volume;
|
||||
|
||||
assertEquals(volume, nc.getComponentVolume(), epsilonPercent * volume);
|
||||
assertEquals(mass, nc.getMass(), epsilonPercent * mass);
|
||||
|
||||
assertEquals(0.8581, cg.x, epsilonPercent * 0.8581);
|
||||
assertEquals(mass, cg.weight, epsilonPercent * mass);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testVolumeSimpleTransitionHollow2() {
|
||||
Transition nc = new Transition();
|
||||
|
||||
final double epsilonPercent = 0.001;
|
||||
final double density = 2.0;
|
||||
|
||||
nc.setLength(1.0);
|
||||
nc.setType(Transition.Shape.CONICAL);
|
||||
nc.setForeRadius(0.5);
|
||||
nc.setAftRadius(1.0);
|
||||
nc.setThickness(0.25);
|
||||
nc.setMaterial(Material.newMaterial(Material.Type.BULK, "test", density, true));
|
||||
|
||||
Coordinate cg = nc.getCG();
|
||||
|
||||
// Volume of filled transition =
|
||||
double filledVolume = Math.PI / 3.0 * (1.0 * 1.0 + 1.0 * 0.5 + 0.5 * 0.5) * 1.0;
|
||||
|
||||
// magic 2D cad drawing...
|
||||
//
|
||||
// Since the thickness < fore radius, the
|
||||
// hollowed out portion of the transition
|
||||
// forms a transition.
|
||||
// the dimensions of this transition were determined
|
||||
// using a 2d cad tool.
|
||||
|
||||
double innerTransitionAftRadius = 0.7205;
|
||||
double innerTransitionForeRadius = 0.2205;
|
||||
double innerVolume = Math.PI / 3.0
|
||||
* (innerTransitionAftRadius * innerTransitionAftRadius + innerTransitionAftRadius * innerTransitionForeRadius + innerTransitionForeRadius * innerTransitionForeRadius);
|
||||
|
||||
double volume = filledVolume - innerVolume;
|
||||
double mass = density * volume;
|
||||
|
||||
assertEquals(volume, nc.getComponentVolume(), epsilonPercent * volume);
|
||||
assertEquals(mass, nc.getMass(), epsilonPercent * mass);
|
||||
|
||||
assertEquals(0.56827, cg.x, epsilonPercent * 0.56827);
|
||||
assertEquals(mass, cg.weight, epsilonPercent * mass);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testVolumeSimpleTransitionWithShouldersHollow2() {
|
||||
Transition nc = new Transition();
|
||||
|
||||
final double epsilonPercent = 0.001;
|
||||
final double density = 2.0;
|
||||
|
||||
nc.setLength(1.0);
|
||||
nc.setType(Transition.Shape.CONICAL);
|
||||
nc.setForeRadius(0.5);
|
||||
nc.setAftRadius(1.0);
|
||||
nc.setThickness(0.25);
|
||||
nc.setAftShoulderLength(1.0);
|
||||
nc.setAftShoulderRadius(1.0);
|
||||
nc.setAftShoulderThickness(0.25);
|
||||
nc.setForeShoulderLength(1.0);
|
||||
nc.setForeShoulderRadius(0.5);
|
||||
nc.setForeShoulderThickness(0.25);
|
||||
|
||||
nc.setMaterial(Material.newMaterial(Material.Type.BULK, "test", density, true));
|
||||
|
||||
Coordinate cg = nc.getCG();
|
||||
|
||||
// Volume of filled transition =
|
||||
double filledVolume = Math.PI / 3.0 * (1.0 * 1.0 + 1.0 * 0.5 + 0.5 * 0.5) * 1.0;
|
||||
|
||||
// magic 2D cad drawing...
|
||||
//
|
||||
// Since the thickness < fore radius, the
|
||||
// hollowed out portion of the transition
|
||||
// forms a transition.
|
||||
// the dimensions of this transition were determined
|
||||
// using a 2d cad tool.
|
||||
|
||||
double innerTransitionAftRadius = 0.7205;
|
||||
double innerTransitionForeRadius = 0.2205;
|
||||
double innerVolume = Math.PI / 3.0
|
||||
* (innerTransitionAftRadius * innerTransitionAftRadius + innerTransitionAftRadius * innerTransitionForeRadius + innerTransitionForeRadius * innerTransitionForeRadius);
|
||||
|
||||
double volume = filledVolume - innerVolume;
|
||||
|
||||
// now add aft shoulder
|
||||
volume += Math.PI * 1.0 * 1.0 * 1.0 - Math.PI * 1.0 * 0.75 * 0.75;
|
||||
// now add fore shoulder
|
||||
volume += Math.PI * 1.0 * 0.5 * 0.5 - Math.PI * 1.0 * 0.25 * 0.25;
|
||||
|
||||
|
||||
double mass = density * volume;
|
||||
|
||||
assertEquals(volume, nc.getComponentVolume(), epsilonPercent * volume);
|
||||
assertEquals(mass, nc.getMass(), epsilonPercent * mass);
|
||||
|
||||
assertEquals(0.7829, cg.x, epsilonPercent * 0.7829);
|
||||
assertEquals(mass, cg.weight, epsilonPercent * mass);
|
||||
}
|
||||
}
|
||||
|
@ -14,6 +14,7 @@ import net.sf.openrocket.gui.widgets.SelectColorToggleButton;
|
||||
import net.sf.openrocket.l10n.Translator;
|
||||
import net.sf.openrocket.rocketcomponent.AxialStage;
|
||||
import net.sf.openrocket.rocketcomponent.BodyTube;
|
||||
import net.sf.openrocket.rocketcomponent.ComponentAssembly;
|
||||
import net.sf.openrocket.rocketcomponent.ComponentChangeEvent;
|
||||
import net.sf.openrocket.rocketcomponent.FlightConfiguration;
|
||||
import net.sf.openrocket.rocketcomponent.Rocket;
|
||||
@ -40,7 +41,7 @@ public class StageSelector extends JPanel implements StateChangeListener {
|
||||
private void updateButtons( final FlightConfiguration configuration ) {
|
||||
buttons.clear();
|
||||
this.removeAll();
|
||||
List<RocketComponent> assemblies = configuration.getRocket().getChildAssemblies();
|
||||
List<ComponentAssembly> assemblies = configuration.getRocket().getAllChildAssemblies();
|
||||
|
||||
for (RocketComponent stage : assemblies) {
|
||||
if (!(stage instanceof AxialStage)) continue;
|
||||
|
@ -1,5 +1,6 @@
|
||||
package net.sf.openrocket.gui.dialogs.flightconfiguration;
|
||||
|
||||
import java.awt.Color;
|
||||
import java.awt.Dialog;
|
||||
import java.awt.Window;
|
||||
import java.awt.event.ActionEvent;
|
||||
@ -12,6 +13,8 @@ import javax.swing.JPanel;
|
||||
import javax.swing.JTextField;
|
||||
|
||||
import net.miginfocom.swing.MigLayout;
|
||||
import net.sf.openrocket.gui.components.StyledLabel;
|
||||
import net.sf.openrocket.gui.configdialog.CommonStrings;
|
||||
import net.sf.openrocket.gui.util.GUIUtil;
|
||||
import net.sf.openrocket.l10n.Translator;
|
||||
import net.sf.openrocket.rocketcomponent.FlightConfigurationId;
|
||||
@ -28,7 +31,7 @@ public class RenameConfigDialog extends JDialog {
|
||||
|
||||
JPanel panel = new JPanel(new MigLayout("fill"));
|
||||
|
||||
panel.add(new JLabel(trans.get("RenameConfigDialog.lbl.name")), "span, wrap rel");
|
||||
panel.add(new JLabel(trans.get("RenameConfigDialog.lbl.name") + " " + CommonStrings.dagger), "span, wrap rel");
|
||||
|
||||
final JTextField textbox = new JTextField(rocket.getFlightConfiguration(fcid).getNameRaw());
|
||||
panel.add(textbox, "span, w 200lp, growx, wrap para");
|
||||
@ -63,7 +66,15 @@ public class RenameConfigDialog extends JDialog {
|
||||
RenameConfigDialog.this.setVisible(false);
|
||||
}
|
||||
});
|
||||
panel.add(cancel);
|
||||
panel.add(cancel, "wrap para");
|
||||
|
||||
// {motors} & {manufacturers} info
|
||||
String text = "<html>" + CommonStrings.dagger + " " + trans.get("RenameConfigDialog.lbl.infoMotors")
|
||||
+ trans.get("RenameConfigDialog.lbl.infoManufacturers")
|
||||
+ trans.get("RenameConfigDialog.lbl.infoCombination");
|
||||
StyledLabel info = new StyledLabel(text, -2);
|
||||
info.setFontColor(Color.DARK_GRAY);
|
||||
panel.add(info, "spanx, growx, wrap");
|
||||
|
||||
this.add(panel);
|
||||
|
||||
|
@ -710,6 +710,8 @@ public class SimulationPanel extends JPanel {
|
||||
tip += trans.get("simpanel.ttip.noData")+"<br>";
|
||||
break;
|
||||
case LOADED:
|
||||
tip += trans.get("simpanel.ttip.loaded") + "<br>";
|
||||
break;
|
||||
case UPTODATE:
|
||||
tip += trans.get("simpanel.ttip.uptodate") + "<br>";
|
||||
break;
|
||||
|
@ -33,7 +33,7 @@ public class Icons {
|
||||
map.put(Simulation.Status.NOT_SIMULATED, loadImageIcon("pix/spheres/gray-16x16.png", "Not simulated"));
|
||||
map.put(Simulation.Status.CANT_RUN, loadImageIcon("pix/spheres/yellow-16x16.png", "Can't run, no motors assigned."));
|
||||
map.put(Simulation.Status.UPTODATE, loadImageIcon("pix/spheres/green-16x16.png", "Up to date"));
|
||||
map.put(Simulation.Status.LOADED, loadImageIcon("pix/spheres/green-16x16.png", "Up to date"));
|
||||
map.put(Simulation.Status.LOADED, loadImageIcon("pix/spheres/blue-16x16.png", "Loaded from File"));
|
||||
map.put(Simulation.Status.OUTDATED, loadImageIcon("pix/spheres/red-16x16.png", "Out-of-date"));
|
||||
map.put(Simulation.Status.EXTERNAL, loadImageIcon("pix/spheres/blue-16x16.png", "Imported data"));
|
||||
SIMULATION_STATUS_ICON_MAP = Collections.unmodifiableMap(map);
|
||||
|
Loading…
x
Reference in New Issue
Block a user