[#2377] Add booster/pod split functionality
This commit is contained in:
parent
d2fc662a56
commit
940b913dfa
@ -1153,16 +1153,20 @@ ComponentCfgDlg.MultiComponentEdit.ttip = <html>You are editing the following co
|
||||
ComponentCfgDlg.Modify = Modify
|
||||
ComponentCfgDlg.ModifyComponents = Modify components
|
||||
|
||||
!StageConfig
|
||||
StageConfig.tab.Separation = Separation
|
||||
StageConfig.tab.Separation.ttip = Stage separation options
|
||||
StageConfig.separation.lbl.title = Select when this stage separates:
|
||||
StageConfig.separation.lbl.plus = plus
|
||||
StageConfig.separation.lbl.seconds = seconds
|
||||
StageConfig.parallel.radius = Radial Distance:
|
||||
StageConfig.parallel.angle = Angle:
|
||||
StageConfig.parallel.count = Number of Copies:
|
||||
StageConfig.parallel.plus = plus
|
||||
!ComponentAssemblyConfig
|
||||
ComponentAssemblyConfig.tab.Separation = Separation
|
||||
ComponentAssemblyConfig.tab.Separation.ttip = Stage separation options
|
||||
ComponentAssemblyConfig.separation.lbl.title = Select when this stage separates:
|
||||
ComponentAssemblyConfig.separation.lbl.plus = plus
|
||||
ComponentAssemblyConfig.separation.lbl.seconds = seconds
|
||||
ComponentAssemblyConfig.parallel.radius = Radial Distance:
|
||||
ComponentAssemblyConfig.parallel.angle = Angle:
|
||||
ComponentAssemblyConfig.parallel.count = Number of Copies:
|
||||
ComponentAssemblyConfig.parallel.plus = plus
|
||||
ComponentAssemblyConfig.but.splitPods = Split Pods
|
||||
ComponentAssemblyConfig.but.splitPods.ttip = Split the pod set into separate pod components.
|
||||
ComponentAssemblyConfig.but.splitBoosters = Split Boosters
|
||||
ComponentAssemblyConfig.but.splitBoosters.ttip = Split the booster into separate booster components.
|
||||
|
||||
! FinSetConfig
|
||||
FinSetCfg.lbl.FinRotation = Fin rotation:
|
||||
|
||||
@ -989,15 +989,15 @@ ComponentCfgDlg.Modify = تعديل
|
||||
ComponentCfgDlg.ModifyComponents = تعديل المكونات
|
||||
|
||||
!StageConfig
|
||||
StageConfig.tab.Separation = فصل
|
||||
StageConfig.tab.Separation.ttip = خيارات فصل المرحلة
|
||||
StageConfig.separation.lbl.title = :حدد متى تنفصل هذه المرحلة
|
||||
StageConfig.separation.lbl.plus = زائد
|
||||
StageConfig.separation.lbl.seconds = ثواني
|
||||
StageConfig.parallel.radius = :المسافة الشعاعية
|
||||
StageConfig.parallel.angle = :الزاوية
|
||||
StageConfig.parallel.count = :عدد النسخ
|
||||
StageConfig.parallel.plus = زائد
|
||||
ComponentAssemblyConfig.tab.Separation = فصل
|
||||
ComponentAssemblyConfig.tab.Separation.ttip = خيارات فصل المرحلة
|
||||
ComponentAssemblyConfig.separation.lbl.title = :حدد متى تنفصل هذه المرحلة
|
||||
ComponentAssemblyConfig.separation.lbl.plus = زائد
|
||||
ComponentAssemblyConfig.separation.lbl.seconds = ثواني
|
||||
ComponentAssemblyConfig.parallel.radius = :المسافة الشعاعية
|
||||
ComponentAssemblyConfig.parallel.angle = :الزاوية
|
||||
ComponentAssemblyConfig.parallel.count = :عدد النسخ
|
||||
ComponentAssemblyConfig.parallel.plus = زائد
|
||||
|
||||
!EllipticalFinSetConfig
|
||||
EllipticalFinSetCfg.Nbroffins = :عدد الزعانف
|
||||
|
||||
@ -676,11 +676,11 @@ ComponentCfgDlg.configuration = konfigurace
|
||||
ComponentCfgDlg.Modify = Uprav
|
||||
|
||||
!StageConfig
|
||||
StageConfig.tab.Separation = Oddelení
|
||||
StageConfig.tab.Separation.ttip = Vlastnosti oddelení stupne
|
||||
StageConfig.separation.lbl.title = Oznac kdy se má tento stupn oddelit:
|
||||
StageConfig.separation.lbl.plus = plus
|
||||
StageConfig.separation.lbl.seconds = sekundy
|
||||
ComponentAssemblyConfig.tab.Separation = Oddelení
|
||||
ComponentAssemblyConfig.tab.Separation.ttip = Vlastnosti oddelení stupne
|
||||
ComponentAssemblyConfig.separation.lbl.title = Oznac kdy se má tento stupn oddelit:
|
||||
ComponentAssemblyConfig.separation.lbl.plus = plus
|
||||
ComponentAssemblyConfig.separation.lbl.seconds = sekundy
|
||||
|
||||
!EllipticalFinSetConfig
|
||||
EllipticalFinSetCfg.Nbroffins = Pocet stabilizátoru:
|
||||
|
||||
@ -733,11 +733,11 @@ ComponentCfgDlg.configuration = Konfiguration
|
||||
ComponentCfgDlg.Modify = Verändern
|
||||
|
||||
!StageConfig
|
||||
StageConfig.tab.Separation = Stufentrennung
|
||||
StageConfig.tab.Separation.ttip = Stufentrennungs-Optionen
|
||||
StageConfig.separation.lbl.title = Auswählen, wenn diese Stufe getrennt wird:
|
||||
StageConfig.separation.lbl.plus = plus
|
||||
StageConfig.separation.lbl.seconds = Sekunden
|
||||
ComponentAssemblyConfig.tab.Separation = Stufentrennung
|
||||
ComponentAssemblyConfig.tab.Separation.ttip = Stufentrennungs-Optionen
|
||||
ComponentAssemblyConfig.separation.lbl.title = Auswählen, wenn diese Stufe getrennt wird:
|
||||
ComponentAssemblyConfig.separation.lbl.plus = plus
|
||||
ComponentAssemblyConfig.separation.lbl.seconds = Sekunden
|
||||
|
||||
!EllipticalFinSetConfig
|
||||
EllipticalFinSetCfg.Nbroffins = Anzahl der Leitwerke
|
||||
|
||||
@ -1051,12 +1051,12 @@ Stage.Stage = Etapa
|
||||
! StageAction
|
||||
StageAction.Stage = Etapa
|
||||
|
||||
StageConfig.separation.lbl.plus = m\u00e1s
|
||||
StageConfig.separation.lbl.seconds = segundos
|
||||
StageConfig.separation.lbl.title = Seleccione el instante de separaci\u00f3n de esta etapa:
|
||||
ComponentAssemblyConfig.separation.lbl.plus = m\u00e1s
|
||||
ComponentAssemblyConfig.separation.lbl.seconds = segundos
|
||||
ComponentAssemblyConfig.separation.lbl.title = Seleccione el instante de separaci\u00f3n de esta etapa:
|
||||
!StageConfig
|
||||
StageConfig.tab.Separation = Separaci\u00f3n
|
||||
StageConfig.tab.Separation.ttip = Opciones de separaci\u00f3n de etapa
|
||||
ComponentAssemblyConfig.tab.Separation = Separaci\u00f3n
|
||||
ComponentAssemblyConfig.tab.Separation.ttip = Opciones de separaci\u00f3n de etapa
|
||||
|
||||
StorageOptChooser.checkbox.Compfile = Archivo comprimido
|
||||
StorageOptChooser.lbl.Saveopt = Guardar opciones
|
||||
|
||||
@ -1044,12 +1044,12 @@ Stage.Stage = Etage
|
||||
! StageAction
|
||||
StageAction.Stage = Etage
|
||||
|
||||
StageConfig.separation.lbl.plus = plus
|
||||
StageConfig.separation.lbl.seconds = secondes
|
||||
StageConfig.separation.lbl.title = Choisir lorsque cet \u00E9tage se s\u00E9pare:
|
||||
ComponentAssemblyConfig.separation.lbl.plus = plus
|
||||
ComponentAssemblyConfig.separation.lbl.seconds = secondes
|
||||
ComponentAssemblyConfig.separation.lbl.title = Choisir lorsque cet \u00E9tage se s\u00E9pare:
|
||||
!StageConfig
|
||||
StageConfig.tab.Separation = S\u00E9paration
|
||||
StageConfig.tab.Separation.ttip = Options de s\u00E9paration de l'\u00E9tage
|
||||
ComponentAssemblyConfig.tab.Separation = S\u00E9paration
|
||||
ComponentAssemblyConfig.tab.Separation.ttip = Options de s\u00E9paration de l'\u00E9tage
|
||||
|
||||
StorageOptChooser.checkbox.Compfile = Compresse le fichier
|
||||
StorageOptChooser.lbl.Saveopt = Options de sauvegarde
|
||||
|
||||
@ -734,11 +734,11 @@ ComponentCfgDlg.configuration = (configurazione)
|
||||
ComponentCfgDlg.Modify = Modifica
|
||||
|
||||
!StageConfig
|
||||
StageConfig.tab.Separation = Separazione
|
||||
StageConfig.tab.Separation.ttip = Opzioni della separazione dello stadio
|
||||
StageConfig.separation.lbl.title = Seleziona quando questo stadio separa:
|
||||
StageConfig.separation.lbl.plus = pi\u00f9
|
||||
StageConfig.separation.lbl.seconds = secondi
|
||||
ComponentAssemblyConfig.tab.Separation = Separazione
|
||||
ComponentAssemblyConfig.tab.Separation.ttip = Opzioni della separazione dello stadio
|
||||
ComponentAssemblyConfig.separation.lbl.title = Seleziona quando questo stadio separa:
|
||||
ComponentAssemblyConfig.separation.lbl.plus = pi\u00f9
|
||||
ComponentAssemblyConfig.separation.lbl.seconds = secondi
|
||||
|
||||
!EllipticalFinSetConfig
|
||||
EllipticalFinSetCfg.Nbroffins = Numero di pinne:
|
||||
|
||||
@ -764,11 +764,11 @@ ComponentCfgDlg.configuration = \u30B3\u30F3\u30D5\u30A3\u30AE\u30E5\u30EC\u30F
|
||||
ComponentCfgDlg.Modify = \u5909\u66F4
|
||||
|
||||
!StageConfig
|
||||
StageConfig.tab.Separation = \u5206\u96E2
|
||||
StageConfig.tab.Separation.ttip = \u30B9\u30C6\u30FC\u30B8\u5206\u96E2\u30AA\u30D7\u30B7\u30E7\u30F3
|
||||
StageConfig.separation.lbl.title = \u30B9\u30C6\u30FC\u30B8\u304C\u5206\u96E2\u3059\u308B\u6642\u523B\u306E\u9078\u629E\uFF1A
|
||||
StageConfig.separation.lbl.plus = \u30D7\u30E9\u30B9
|
||||
StageConfig.separation.lbl.seconds = \u79D2
|
||||
ComponentAssemblyConfig.tab.Separation = \u5206\u96E2
|
||||
ComponentAssemblyConfig.tab.Separation.ttip = \u30B9\u30C6\u30FC\u30B8\u5206\u96E2\u30AA\u30D7\u30B7\u30E7\u30F3
|
||||
ComponentAssemblyConfig.separation.lbl.title = \u30B9\u30C6\u30FC\u30B8\u304C\u5206\u96E2\u3059\u308B\u6642\u523B\u306E\u9078\u629E\uFF1A
|
||||
ComponentAssemblyConfig.separation.lbl.plus = \u30D7\u30E9\u30B9
|
||||
ComponentAssemblyConfig.separation.lbl.seconds = \u79D2
|
||||
|
||||
!EllipticalFinSetConfig
|
||||
EllipticalFinSetCfg.Nbroffins = \u30D5\u30A3\u30F3\u306E\u6570\uFF1A
|
||||
|
||||
@ -940,14 +940,14 @@ ComponentCfgDlg.configuration = configuratie
|
||||
ComponentCfgDlg.Modify = Wijzigen
|
||||
|
||||
!StageConfig
|
||||
StageConfig.tab.Separation = Afscheiding
|
||||
StageConfig.tab.Separation.ttip = Etape afscheidingsopties
|
||||
StageConfig.separation.lbl.title = Selecteer wanneer deze etape afscheidt:
|
||||
StageConfig.separation.lbl.plus = plus
|
||||
StageConfig.separation.lbl.seconds = seconden
|
||||
StageConfig.parallel.radius = Radiale Afstand
|
||||
StageConfig.parallel.angle = Hoek
|
||||
StageConfig.parallel.count = Aantal kopieën
|
||||
ComponentAssemblyConfig.tab.Separation = Afscheiding
|
||||
ComponentAssemblyConfig.tab.Separation.ttip = Etape afscheidingsopties
|
||||
ComponentAssemblyConfig.separation.lbl.title = Selecteer wanneer deze etape afscheidt:
|
||||
ComponentAssemblyConfig.separation.lbl.plus = plus
|
||||
ComponentAssemblyConfig.separation.lbl.seconds = seconden
|
||||
ComponentAssemblyConfig.parallel.radius = Radiale Afstand
|
||||
ComponentAssemblyConfig.parallel.angle = Hoek
|
||||
ComponentAssemblyConfig.parallel.count = Aantal kopieën
|
||||
StageConfig.parallel.offset = Offset-waarde
|
||||
|
||||
!EllipticalFinSetConfig
|
||||
|
||||
@ -679,11 +679,11 @@ ComponentInfo.EngineBlock = <b>Blokada silnika</b> unieruchamia silnik wewn\u01
|
||||
ComponentCfgDlg.Modify = Zmodyfikuj
|
||||
|
||||
!StageConfig
|
||||
StageConfig.tab.Separation = Separacja
|
||||
StageConfig.tab.Separation.ttip = Opcje oddzielenia cz\u0142onu
|
||||
StageConfig.separation.lbl.title = Ustal moment oddzielenia cz\u0142onu:
|
||||
StageConfig.separation.lbl.plus = plus
|
||||
StageConfig.separation.lbl.seconds = sek.
|
||||
ComponentAssemblyConfig.tab.Separation = Separacja
|
||||
ComponentAssemblyConfig.tab.Separation.ttip = Opcje oddzielenia cz\u0142onu
|
||||
ComponentAssemblyConfig.separation.lbl.title = Ustal moment oddzielenia cz\u0142onu:
|
||||
ComponentAssemblyConfig.separation.lbl.plus = plus
|
||||
ComponentAssemblyConfig.separation.lbl.seconds = sek.
|
||||
|
||||
!EllipticalFinSetConfig
|
||||
EllipticalFinSetCfg.Nbroffins = Liczba stateczników:
|
||||
|
||||
@ -1020,12 +1020,12 @@ Stage.Stage = Etapa
|
||||
# StageAction
|
||||
StageAction.Stage = Est\u00e1gio
|
||||
|
||||
StageConfig.separation.lbl.plus = mais
|
||||
StageConfig.separation.lbl.seconds = segundos
|
||||
StageConfig.separation.lbl.title = Selecione quando este est\u00e1gio separa:
|
||||
ComponentAssemblyConfig.separation.lbl.plus = mais
|
||||
ComponentAssemblyConfig.separation.lbl.seconds = segundos
|
||||
ComponentAssemblyConfig.separation.lbl.title = Selecione quando este est\u00e1gio separa:
|
||||
# StageConfig
|
||||
StageConfig.tab.Separation = Separa\u00e7\u00e3o
|
||||
StageConfig.tab.Separation.ttip = Op\u00e7\u00f5es de separa\u00e7\u00e3o de est\u00e1gio
|
||||
ComponentAssemblyConfig.tab.Separation = Separa\u00e7\u00e3o
|
||||
ComponentAssemblyConfig.tab.Separation.ttip = Op\u00e7\u00f5es de separa\u00e7\u00e3o de est\u00e1gio
|
||||
|
||||
StorageOptChooser.checkbox.Compfile = Compactar arquivos
|
||||
StorageOptChooser.lbl.Saveopt = Salvar as Op\u00e7\u00f5es
|
||||
|
||||
@ -968,15 +968,15 @@ ComponentCfgDlg.Modify = \u0418\u0437\u043C\u0435\u043D\u0438\u0442\u044C
|
||||
ComponentCfgDlg.ModifyComponents = \u0418\u0437\u043C\u0435\u043D\u0438\u0442\u044C \u043A\u043E\u043C\u043F\u043E\u043D\u0435\u043D\u0442\u044B
|
||||
|
||||
!StageConfig
|
||||
StageConfig.tab.Separation = \u0420\u0430\u0437\u0434\u0435\u043B\u0435\u043D\u0438\u0435
|
||||
StageConfig.tab.Separation.ttip = \u041D\u0430\u0441\u0442\u0440\u043E\u0439\u043A\u0438 \u0440\u0430\u0437\u0434\u0435\u043B\u0435\u043D\u0438\u044F \u0441\u0442\u0443\u043F\u0435\u043D\u0435\u0439
|
||||
StageConfig.separation.lbl.title = \u0412\u044B\u0431\u0435\u0440\u0438\u0442\u0435, \u043A\u043E\u0433\u0434\u0430 \u044D\u0442\u0430 \u0441\u0442\u0443\u043F\u0435\u043D\u044C \u043E\u0442\u0434\u0435\u043B\u044F\u0435\u0442\u0441\u044F:
|
||||
StageConfig.separation.lbl.plus = \u043F\u043B\u044E\u0441
|
||||
StageConfig.separation.lbl.seconds = \u0441\u0435\u043A\u0443\u043D\u0434
|
||||
StageConfig.parallel.radius = \u0420\u0430\u0434\u0438\u0430\u043B\u044C\u043D\u043E\u0435 \u0440\u0430\u0441\u0441\u0442\u043E\u044F\u043D\u0438\u0435:
|
||||
StageConfig.parallel.angle = \u0423\u0433\u043E\u043B:
|
||||
StageConfig.parallel.count = \u041A\u043E\u043B\u0438\u0447\u0435\u0441\u0442\u0432\u043E \u043A\u043E\u043F\u0438\u0439:
|
||||
StageConfig.parallel.plus = \u043F\u043B\u044E\u0441
|
||||
ComponentAssemblyConfig.tab.Separation = \u0420\u0430\u0437\u0434\u0435\u043B\u0435\u043D\u0438\u0435
|
||||
ComponentAssemblyConfig.tab.Separation.ttip = \u041D\u0430\u0441\u0442\u0440\u043E\u0439\u043A\u0438 \u0440\u0430\u0437\u0434\u0435\u043B\u0435\u043D\u0438\u044F \u0441\u0442\u0443\u043F\u0435\u043D\u0435\u0439
|
||||
ComponentAssemblyConfig.separation.lbl.title = \u0412\u044B\u0431\u0435\u0440\u0438\u0442\u0435, \u043A\u043E\u0433\u0434\u0430 \u044D\u0442\u0430 \u0441\u0442\u0443\u043F\u0435\u043D\u044C \u043E\u0442\u0434\u0435\u043B\u044F\u0435\u0442\u0441\u044F:
|
||||
ComponentAssemblyConfig.separation.lbl.plus = \u043F\u043B\u044E\u0441
|
||||
ComponentAssemblyConfig.separation.lbl.seconds = \u0441\u0435\u043A\u0443\u043D\u0434
|
||||
ComponentAssemblyConfig.parallel.radius = \u0420\u0430\u0434\u0438\u0430\u043B\u044C\u043D\u043E\u0435 \u0440\u0430\u0441\u0441\u0442\u043E\u044F\u043D\u0438\u0435:
|
||||
ComponentAssemblyConfig.parallel.angle = \u0423\u0433\u043E\u043B:
|
||||
ComponentAssemblyConfig.parallel.count = \u041A\u043E\u043B\u0438\u0447\u0435\u0441\u0442\u0432\u043E \u043A\u043E\u043F\u0438\u0439:
|
||||
ComponentAssemblyConfig.parallel.plus = \u043F\u043B\u044E\u0441
|
||||
|
||||
!EllipticalFinSetConfig
|
||||
EllipticalFinSetCfg.Nbroffins = \u041A\u043E\u043B\u0438\u0447\u0435\u0441\u0442\u0432\u043E \u0441\u0442\u0430\u0431\u0438\u043B\u0438\u0437\u0430\u0442\u043E\u0440\u043E\u0432:
|
||||
|
||||
@ -838,11 +838,11 @@ ComponentCfgDlg.configuration = configuration
|
||||
ComponentCfgDlg.Modify = Modify
|
||||
|
||||
!StageConfig
|
||||
StageConfig.tab.Separation = Separation
|
||||
StageConfig.tab.Separation.ttip = Stage separation options
|
||||
StageConfig.separation.lbl.title = Select when this stage separates:
|
||||
StageConfig.separation.lbl.plus = plus
|
||||
StageConfig.separation.lbl.seconds = seconds
|
||||
ComponentAssemblyConfig.tab.Separation = Separation
|
||||
ComponentAssemblyConfig.tab.Separation.ttip = Stage separation options
|
||||
ComponentAssemblyConfig.separation.lbl.title = Select when this stage separates:
|
||||
ComponentAssemblyConfig.separation.lbl.plus = plus
|
||||
ComponentAssemblyConfig.separation.lbl.seconds = seconds
|
||||
|
||||
!EllipticalFinSetConfig
|
||||
EllipticalFinSetCfg.Nbroffins = Number of fins:
|
||||
|
||||
@ -1120,12 +1120,12 @@ Stage.Stage = \u706B\u7BAD\u7EA7
|
||||
! StageAction
|
||||
StageAction.Stage = \u7EA7
|
||||
|
||||
StageConfig.separation.lbl.plus = \u52A0
|
||||
StageConfig.separation.lbl.seconds = \u79D2
|
||||
StageConfig.separation.lbl.title = \u8BBE\u5B9A\u5206\u79BB\u65F6\u673A:
|
||||
ComponentAssemblyConfig.separation.lbl.plus = \u52A0
|
||||
ComponentAssemblyConfig.separation.lbl.seconds = \u79D2
|
||||
ComponentAssemblyConfig.separation.lbl.title = \u8BBE\u5B9A\u5206\u79BB\u65F6\u673A:
|
||||
!StageConfig
|
||||
StageConfig.tab.Separation = \u5206\u79BB
|
||||
StageConfig.tab.Separation.ttip = \u591A\u7EA7\u5206\u79BB\u9009\u9879
|
||||
ComponentAssemblyConfig.tab.Separation = \u5206\u79BB
|
||||
ComponentAssemblyConfig.tab.Separation.ttip = \u591A\u7EA7\u5206\u79BB\u9009\u9879
|
||||
|
||||
StorageOptChooser.lbl.Saveopt = \u4FDD\u5B58\u9009\u9879
|
||||
! StorageOptionChooser
|
||||
|
||||
@ -242,7 +242,9 @@ public class AxialStage extends ComponentAssembly implements FlightConfigurableC
|
||||
public void clearConfigListeners() {
|
||||
super.clearConfigListeners();
|
||||
// StageSeparationConfiguration also has config listeners, so clear them as well
|
||||
StageSeparationConfiguration thisConfig = getSeparationConfiguration();
|
||||
thisConfig.clearConfigListeners();
|
||||
if (getRoot() instanceof Rocket) { // Root can be different from the rocket if this stage (or its parent) has been removed from the rocket
|
||||
StageSeparationConfiguration thisConfig = getSeparationConfiguration();
|
||||
thisConfig.clearConfigListeners();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -1478,61 +1478,18 @@ public abstract class FinSet extends ExternalComponent implements AxialPositiona
|
||||
|
||||
/**
|
||||
* Split the fin set into individual fins.
|
||||
* @return A list of the new fin sets.
|
||||
*
|
||||
* @return A list of the new fin sets.
|
||||
*/
|
||||
public List<FinSet> splitFins(boolean freezeRocket) {
|
||||
final RocketComponent root = getRoot();
|
||||
RocketComponent parent = getParent();
|
||||
int index = parent.getChildPosition(this);
|
||||
int count = getFinCount();
|
||||
double base = getBaseRotation();
|
||||
|
||||
List<FinSet> splitFins = null; // List of all the split fins
|
||||
|
||||
try {
|
||||
// Freeze rocket
|
||||
if (freezeRocket && root instanceof Rocket) {
|
||||
((Rocket) root).freeze();
|
||||
}
|
||||
|
||||
// Split the fins
|
||||
if (count > 1) {
|
||||
parent.removeChild(index);
|
||||
splitFins = new ArrayList<>();
|
||||
for (int i = 0; i < count; i++) {
|
||||
FinSet copy = (FinSet) this.copy();
|
||||
copy.setFinCount(1);
|
||||
copy.setBaseRotation(base + i * 2 * Math.PI / count);
|
||||
copy.setName(copy.getName() + " #" + (i + 1));
|
||||
copy.setOverrideMass(getOverrideMass() / getFinCount());
|
||||
parent.addChild(copy, index + i);
|
||||
|
||||
splitFins.add(copy);
|
||||
}
|
||||
}
|
||||
|
||||
// Split fins for children
|
||||
for (RocketComponent listener : configListeners) {
|
||||
if (listener instanceof FinSet) {
|
||||
((FinSet) listener).splitFins(false);
|
||||
this.removeConfigListener(listener);
|
||||
}
|
||||
}
|
||||
} finally {
|
||||
// Unfreeze rocket
|
||||
if (freezeRocket && root instanceof Rocket) {
|
||||
((Rocket) root).thaw();
|
||||
}
|
||||
}
|
||||
|
||||
return splitFins;
|
||||
public List<RocketComponent> splitFins(boolean freezeRocket) {
|
||||
return splitInstances(freezeRocket);
|
||||
}
|
||||
|
||||
/**
|
||||
* Split the fin set into individual fins.
|
||||
* @return A list of the new fin sets.
|
||||
*/
|
||||
public List<FinSet> splitFins() {
|
||||
public List<RocketComponent> splitFins() {
|
||||
return splitFins(true);
|
||||
}
|
||||
|
||||
|
||||
@ -5,7 +5,7 @@ import net.sf.openrocket.util.Coordinate;
|
||||
public interface Instanceable {
|
||||
|
||||
@Deprecated
|
||||
public Coordinate[] getLocations();
|
||||
Coordinate[] getLocations();
|
||||
|
||||
/**
|
||||
* Returns vector coordinates of each instance of this component relative to this component's parent
|
||||
@ -16,7 +16,7 @@ public interface Instanceable {
|
||||
*
|
||||
* @return coordinates location of each instance relative to component's parent
|
||||
*/
|
||||
public Coordinate[] getInstanceLocations();
|
||||
Coordinate[] getInstanceLocations();
|
||||
|
||||
/**
|
||||
* Returns vector coordinates of each instance of this component relative to this component's reference point (typically front center)
|
||||
@ -27,20 +27,20 @@ public interface Instanceable {
|
||||
*
|
||||
* @return coordinates location of each instance relative to <b>this</b> component's reference point.
|
||||
*/
|
||||
public Coordinate[] getInstanceOffsets();
|
||||
Coordinate[] getInstanceOffsets();
|
||||
|
||||
/**
|
||||
* How many instances of this component are represented. This should generally be editable.
|
||||
* @param newCount number of instances to set
|
||||
*/
|
||||
public void setInstanceCount( final int newCount );
|
||||
void setInstanceCount( final int newCount );
|
||||
|
||||
/**
|
||||
* How many instances of this component are represented. This should generally be editable.
|
||||
*
|
||||
* @return number of instances this component currently represent.
|
||||
*/
|
||||
public int getInstanceCount();
|
||||
int getInstanceCount();
|
||||
|
||||
/**
|
||||
* Get a human-readable name for this instance arrangement.
|
||||
@ -48,6 +48,6 @@ public interface Instanceable {
|
||||
*
|
||||
* @return pattern name
|
||||
*/
|
||||
public String getPatternName();
|
||||
String getPatternName();
|
||||
|
||||
}
|
||||
|
||||
@ -412,7 +412,9 @@ public class Rocket extends ComponentAssembly {
|
||||
* changes.
|
||||
*/
|
||||
public void loadFrom(Rocket source) {
|
||||
|
||||
checkState();
|
||||
mutex.lock("loadFrom");
|
||||
|
||||
// Store list of components to invalidate after event has been fired
|
||||
List<RocketComponent> toInvalidate = this.copyFrom(source);
|
||||
|
||||
@ -453,6 +455,8 @@ public class Rocket extends ComponentAssembly {
|
||||
for (RocketComponent c : toInvalidate) {
|
||||
c.invalidate();
|
||||
}
|
||||
|
||||
mutex.unlock("loadFrom");
|
||||
}
|
||||
|
||||
|
||||
|
||||
@ -15,6 +15,7 @@ import net.sf.openrocket.aerodynamics.AerodynamicForces;
|
||||
import net.sf.openrocket.aerodynamics.BarrowmanCalculator;
|
||||
import net.sf.openrocket.aerodynamics.FlightConditions;
|
||||
import net.sf.openrocket.logging.WarningSet;
|
||||
import net.sf.openrocket.rocketcomponent.position.AnglePositionable;
|
||||
import net.sf.openrocket.startup.Application;
|
||||
import net.sf.openrocket.startup.Preferences;
|
||||
import net.sf.openrocket.util.ORColor;
|
||||
@ -1088,6 +1089,11 @@ public abstract class RocketComponent implements ChangeSource, Cloneable, Iterab
|
||||
public int getInstanceCount() {
|
||||
return 1;
|
||||
}
|
||||
|
||||
public void setInstanceCount(int count) {
|
||||
// Do nothing
|
||||
log.warn("setInstanceCount called on component that does not support multiple instances");
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the user-defined name of the component.
|
||||
@ -2382,12 +2388,16 @@ public abstract class RocketComponent implements ChangeSource, Cloneable, Iterab
|
||||
*/
|
||||
public final RocketComponent findComponent(String idToFind) {
|
||||
checkState();
|
||||
mutex.lock("findComponent");
|
||||
Iterator<RocketComponent> iter = this.iterator(true);
|
||||
while (iter.hasNext()) {
|
||||
final RocketComponent c = iter.next();
|
||||
if (c.getID().equals(idToFind))
|
||||
if (c.getID().equals(idToFind)) {
|
||||
mutex.unlock("findComponent");
|
||||
return c;
|
||||
}
|
||||
}
|
||||
mutex.unlock("findComponent");
|
||||
return null;
|
||||
}
|
||||
|
||||
@ -2440,6 +2450,67 @@ public abstract class RocketComponent implements ChangeSource, Cloneable, Iterab
|
||||
return c;
|
||||
}
|
||||
|
||||
/**
|
||||
* Split the current multi-instance component into multiple single-instance components.
|
||||
* @param freezeRocket whether to freeze the rocket while splitting
|
||||
* @return list of all the split components
|
||||
*/
|
||||
public List<RocketComponent> splitInstances(boolean freezeRocket) {
|
||||
final Rocket rocket = getRocket();
|
||||
RocketComponent parent = getParent();
|
||||
int index = parent.getChildPosition(this);
|
||||
int count = getInstanceCount();
|
||||
double angleOffset = getAngleOffset();
|
||||
|
||||
List<RocketComponent> splitComponents = null; // List of all the split components
|
||||
|
||||
try {
|
||||
// Freeze rocket
|
||||
if (freezeRocket) {
|
||||
rocket.freeze();
|
||||
}
|
||||
|
||||
// Split the components
|
||||
if (count > 1) {
|
||||
parent.removeChild(index, true); // Remove the original component
|
||||
splitComponents = new java.util.ArrayList<>();
|
||||
for (int i = 0; i < count; i++) {
|
||||
RocketComponent copy = this.copy();
|
||||
copy.setInstanceCount(1);
|
||||
if (copy instanceof AnglePositionable) {
|
||||
((AnglePositionable) copy).setAngleOffset(angleOffset + i * 2 * Math.PI / count);
|
||||
}
|
||||
copy.setName(copy.getName() + " #" + (i + 1));
|
||||
copy.setOverrideMass(getOverrideMass() / count);
|
||||
parent.addChild(copy, index + i, true); // Add the new component
|
||||
|
||||
splitComponents.add(copy);
|
||||
}
|
||||
}
|
||||
|
||||
// Split components for listeners
|
||||
for (RocketComponent listener : configListeners) {
|
||||
if (listener.getClass().isAssignableFrom(this.getClass())) {
|
||||
listener.splitInstances(false);
|
||||
this.removeConfigListener(listener);
|
||||
}
|
||||
}
|
||||
} finally {
|
||||
// Unfreeze rocket
|
||||
if (freezeRocket) {
|
||||
rocket.thaw();
|
||||
}
|
||||
}
|
||||
|
||||
fireComponentChangeEvent(ComponentChangeEvent.TREE_CHANGE);
|
||||
|
||||
return splitComponents;
|
||||
}
|
||||
|
||||
public List<RocketComponent> splitInstances() {
|
||||
return splitInstances(true);
|
||||
}
|
||||
|
||||
/////////// Event handling //////////
|
||||
//
|
||||
// Listener lists are provided by the root Rocket component,
|
||||
|
||||
@ -1000,6 +1000,9 @@ public class DoubleModel implements StateChangeListener, ChangeSource, Invalidat
|
||||
log.warn("Invalidating " + this + " while still having listeners " + listeners);
|
||||
}
|
||||
listeners.clear();
|
||||
if (source instanceof ChangeSource) {
|
||||
((ChangeSource) source).removeChangeListener(this);
|
||||
}
|
||||
MemoryManagement.collectable(this);
|
||||
}
|
||||
|
||||
|
||||
@ -31,8 +31,8 @@ public class AxialStageConfig extends ComponentAssemblyConfig {
|
||||
// Stage separation config (for non-first stage)
|
||||
if (component.getStageNumber() > 0) {
|
||||
JPanel tab = separationTab((AxialStage) component);
|
||||
tabbedPane.insertTab(trans.get("StageConfig.tab.Separation"), null, tab,
|
||||
trans.get("StageConfig.tab.Separation.ttip"), 0);
|
||||
tabbedPane.insertTab(trans.get("ComponentAssemblyConfig.tab.Separation"), null, tab,
|
||||
trans.get("ComponentAssemblyConfig.tab.Separation.ttip"), 0);
|
||||
tabbedPane.setSelectedIndex(0);
|
||||
}
|
||||
|
||||
@ -49,7 +49,7 @@ public class AxialStageConfig extends ComponentAssemblyConfig {
|
||||
JPanel panel = new JPanel(new MigLayout());
|
||||
|
||||
// Select separation event
|
||||
panel.add(new StyledLabel(trans.get("StageConfig.separation.lbl.title") + " " + CommonStrings.dagger, Style.BOLD),
|
||||
panel.add(new StyledLabel(trans.get("ComponentAssemblyConfig.separation.lbl.title") + " " + CommonStrings.dagger, Style.BOLD),
|
||||
"spanx, gaptop unrel, wrap 30lp");
|
||||
|
||||
StageSeparationConfiguration sepConfig = stage.getSeparationConfiguration();
|
||||
@ -61,7 +61,7 @@ public class AxialStageConfig extends ComponentAssemblyConfig {
|
||||
order.add(combo);
|
||||
|
||||
// ... and delay
|
||||
panel.add(new JLabel(trans.get("StageConfig.separation.lbl.plus")));
|
||||
panel.add(new JLabel(trans.get("ComponentAssemblyConfig.separation.lbl.plus")));
|
||||
|
||||
DoubleModel dm = new DoubleModel( sepConfig, "SeparationDelay", 0);
|
||||
JSpinner spin = new JSpinner(dm.getSpinnerModel());
|
||||
@ -70,7 +70,7 @@ public class AxialStageConfig extends ComponentAssemblyConfig {
|
||||
order.add(((SpinnerEditor)spin.getEditor()).getTextField());
|
||||
|
||||
//// seconds
|
||||
panel.add(new JLabel(trans.get("StageConfig.separation.lbl.seconds")), "wrap unrel");
|
||||
panel.add(new JLabel(trans.get("ComponentAssemblyConfig.separation.lbl.seconds")), "wrap unrel");
|
||||
|
||||
panel.add(new StyledLabel(CommonStrings.override_description, -1), "spanx, pushy, wrap para");
|
||||
|
||||
|
||||
@ -1,11 +1,13 @@
|
||||
package net.sf.openrocket.gui.configdialog;
|
||||
|
||||
import javax.swing.ComboBoxModel;
|
||||
import javax.swing.JButton;
|
||||
import javax.swing.JComboBox;
|
||||
import javax.swing.JDialog;
|
||||
import javax.swing.JLabel;
|
||||
import javax.swing.JPanel;
|
||||
import javax.swing.JSpinner;
|
||||
import javax.swing.SwingUtilities;
|
||||
|
||||
import net.miginfocom.swing.MigLayout;
|
||||
import net.sf.openrocket.document.OpenRocketDocument;
|
||||
@ -15,27 +17,35 @@ import net.sf.openrocket.gui.adaptors.EnumModel;
|
||||
import net.sf.openrocket.gui.adaptors.IntegerModel;
|
||||
import net.sf.openrocket.gui.components.BasicSlider;
|
||||
import net.sf.openrocket.gui.components.UnitSelector;
|
||||
import net.sf.openrocket.gui.widgets.SelectColorButton;
|
||||
import net.sf.openrocket.l10n.Translator;
|
||||
import net.sf.openrocket.logging.Markers;
|
||||
import net.sf.openrocket.rocketcomponent.ComponentAssembly;
|
||||
import net.sf.openrocket.rocketcomponent.ParallelStage;
|
||||
import net.sf.openrocket.rocketcomponent.PodSet;
|
||||
import net.sf.openrocket.rocketcomponent.RocketComponent;
|
||||
import net.sf.openrocket.rocketcomponent.position.AxialMethod;
|
||||
import net.sf.openrocket.rocketcomponent.position.RadiusMethod;
|
||||
import net.sf.openrocket.startup.Application;
|
||||
import net.sf.openrocket.unit.UnitGroup;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import java.awt.event.ActionEvent;
|
||||
import java.awt.event.ActionListener;
|
||||
import java.awt.event.ItemEvent;
|
||||
import java.awt.event.ItemListener;
|
||||
import java.util.ArrayList;
|
||||
import java.util.EventObject;
|
||||
import java.util.List;
|
||||
|
||||
|
||||
@SuppressWarnings("serial")
|
||||
public class ComponentAssemblyConfig extends RocketComponentConfig {
|
||||
private static final Translator trans = Application.getTranslator();
|
||||
private static final Logger log = LoggerFactory.getLogger(ComponentAssemblyConfig.class);
|
||||
private final RocketComponent component;
|
||||
|
||||
private JButton split = null;
|
||||
|
||||
public ComponentAssemblyConfig(OpenRocketDocument document, RocketComponent component, JDialog parent) {
|
||||
super(document, component, parent);
|
||||
@ -46,6 +56,8 @@ public class ComponentAssemblyConfig extends RocketComponentConfig {
|
||||
tabbedPane.insertTab( trans.get("RocketCompCfg.tab.Assembly"), null, parallelTab( (ComponentAssembly)component ),
|
||||
trans.get("RocketCompCfg.tab.AssemblyComment"), 0);
|
||||
tabbedPane.setSelectedIndex(0);
|
||||
|
||||
addSplitButton();
|
||||
}
|
||||
}
|
||||
|
||||
@ -62,7 +74,7 @@ public class ComponentAssemblyConfig extends RocketComponentConfig {
|
||||
order.add(radiusMethodCombo);
|
||||
|
||||
// set radial distance
|
||||
JLabel radiusLabel = new JLabel(trans.get("StageConfig.parallel.radius"));
|
||||
JLabel radiusLabel = new JLabel(trans.get("ComponentAssemblyConfig.parallel.radius"));
|
||||
motherPanel.add( radiusLabel , "align left");
|
||||
//radiusMethodModel.addEnableComponent(radiusLabel, false);
|
||||
DoubleModel radiusModel = new DoubleModel( boosters, "RadiusOffset", UnitGroup.UNITS_LENGTH, 0);
|
||||
@ -85,7 +97,7 @@ public class ComponentAssemblyConfig extends RocketComponentConfig {
|
||||
});
|
||||
|
||||
// set angle
|
||||
JLabel angleLabel = new JLabel(trans.get("StageConfig.parallel.angle"));
|
||||
JLabel angleLabel = new JLabel(trans.get("ComponentAssemblyConfig.parallel.angle"));
|
||||
motherPanel.add( angleLabel, "align left");
|
||||
DoubleModel angleModel = new DoubleModel( boosters, "AngleOffset", 1.0, UnitGroup.UNITS_ANGLE, -Math.PI, Math.PI);
|
||||
|
||||
@ -98,7 +110,7 @@ public class ComponentAssemblyConfig extends RocketComponentConfig {
|
||||
motherPanel.add(new BasicSlider(angleModel.getSliderModel(-Math.PI, Math.PI)), "gapleft para, growx 2, wrap");
|
||||
|
||||
// set multiplicity
|
||||
JLabel countLabel = new JLabel(trans.get("StageConfig.parallel.count"));
|
||||
JLabel countLabel = new JLabel(trans.get("ComponentAssemblyConfig.parallel.count"));
|
||||
motherPanel.add( countLabel, "align left");
|
||||
|
||||
IntegerModel countModel = new IntegerModel( boosters, "InstanceCount", 1);
|
||||
@ -112,4 +124,64 @@ public class ComponentAssemblyConfig extends RocketComponentConfig {
|
||||
|
||||
return motherPanel;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updateFields() {
|
||||
super.updateFields();
|
||||
if (split != null) {
|
||||
split.setEnabled(component.getInstanceCount() > 1);
|
||||
}
|
||||
}
|
||||
|
||||
private void addSplitButton() {
|
||||
//// Split fins
|
||||
final String btnText;
|
||||
final String btnTextTtip;
|
||||
final boolean freezeRocket;
|
||||
if (PodSet.class.isAssignableFrom(component.getClass())) {
|
||||
btnText = trans.get("ComponentAssemblyConfig.but.splitPods");
|
||||
btnTextTtip = trans.get("ComponentAssemblyConfig.but.splitPods.ttip");
|
||||
freezeRocket = true;
|
||||
} else if (ParallelStage.class.isAssignableFrom(component.getClass())) {
|
||||
btnText = trans.get("ComponentAssemblyConfig.but.splitBoosters");
|
||||
btnTextTtip = trans.get("ComponentAssemblyConfig.but.splitBoosters.ttip");
|
||||
freezeRocket = false;
|
||||
} else {
|
||||
return;
|
||||
}
|
||||
split = new SelectColorButton(btnText);
|
||||
split.setToolTipText(btnTextTtip);
|
||||
split.addActionListener(new ActionListener() {
|
||||
@Override
|
||||
public void actionPerformed(ActionEvent e) {
|
||||
log.info(Markers.USER_MARKER, "Splitting " + component.getComponentName() + " into separate assemblies, instance count=" +
|
||||
component.getInstanceCount());
|
||||
|
||||
// This is a bit awkward, we need to store the listeners before closing the dialog, because closing it
|
||||
// will remove them. We then add them back before the split and remove them afterwards.
|
||||
List<RocketComponent> listeners = new ArrayList<>(component.getConfigListeners());
|
||||
|
||||
|
||||
// Do change in future for overall safety
|
||||
SwingUtilities.invokeLater(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
disposeDialog();
|
||||
|
||||
document.startUndo("Split assembly");
|
||||
for (RocketComponent listener : listeners) {
|
||||
component.addConfigListener(listener);
|
||||
}
|
||||
component.splitInstances(freezeRocket);
|
||||
component.clearConfigListeners();
|
||||
document.stopUndo();
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
split.setEnabled(component.getInstanceCount() > 1);
|
||||
|
||||
addButtons(split);
|
||||
order.add(split);
|
||||
}
|
||||
}
|
||||
|
||||
@ -339,6 +339,7 @@ public class RocketComponentConfig extends JPanel {
|
||||
}
|
||||
|
||||
protected void disposeDialog() {
|
||||
invalidate();
|
||||
if (parent != null) {
|
||||
if (parent instanceof ComponentConfigDialog) {
|
||||
ComponentConfigDialog.disposeDialog();
|
||||
@ -700,6 +701,7 @@ public class RocketComponentConfig extends JPanel {
|
||||
panel.add(checkboxes, "growx 1, gapright 20lp");
|
||||
|
||||
m = new DoubleModel(component, "OverrideCD", UnitGroup.UNITS_COEFFICIENT, Double.NEGATIVE_INFINITY, Double.POSITIVE_INFINITY);
|
||||
register(m);
|
||||
spin = new JSpinner(m.getSpinnerModel());
|
||||
|
||||
spin.setEditor(new SpinnerEditor(spin));
|
||||
|
||||
@ -82,7 +82,7 @@ public class SeparationSelectionDialog extends JDialog {
|
||||
panel.add(event, "wrap rel");
|
||||
|
||||
// ... and delay
|
||||
panel.add(new JLabel(trans.get("StageConfig.separation.lbl.plus")), "alignx 100%");
|
||||
panel.add(new JLabel(trans.get("ComponentAssemblyConfig.separation.lbl.plus")), "alignx 100%");
|
||||
|
||||
final DoubleModel delay = new DoubleModel(newConfiguration, "SeparationDelay", UnitGroup.UNITS_SHORT_TIME, 0);
|
||||
JSpinner spin = new JSpinner(delay.getSpinnerModel());
|
||||
@ -90,7 +90,7 @@ public class SeparationSelectionDialog extends JDialog {
|
||||
panel.add(spin, "span, split");
|
||||
|
||||
//// seconds
|
||||
panel.add(new JLabel(trans.get("StageConfig.separation.lbl.seconds")), "wrap para");
|
||||
panel.add(new JLabel(trans.get("ComponentAssemblyConfig.separation.lbl.seconds")), "wrap para");
|
||||
|
||||
|
||||
panel.add(new JPanel(), "span, split, growx");
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user