Merge branch 'openrocket:unstable' into scripting

This commit is contained in:
thzero 2022-07-20 08:28:17 -05:00 committed by GitHub
commit e35b7bda2d
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
73 changed files with 1507 additions and 293 deletions

View File

@ -15,6 +15,8 @@
<classpathentry kind="lib" path="lib-extra/RXTXcomm.jar"/>
<classpathentry kind="lib" path="resources"/>
<classpathentry kind="lib" path="lib/javax.inject.jar"/>
<classpathentry kind="lib" path="lib/javax.json-1.1.3.jar"/>
<classpathentry kind="lib" path="lib/javax.json-api-1.1.3.jar"/>
<classpathentry kind="lib" path="lib/aopalliance.jar"/>
<classpathentry kind="lib" path="lib/commonmark-0.19.0.jar"/>
<classpathentry kind="lib" path="lib/slf4j-api-1.7.30.jar"/>

View File

@ -294,6 +294,8 @@ pref.dlg.lbl.PositiontoinsertStages = Position to insert new stages:
pref.dlg.lbl.Confirmdeletion = Confirm deletion of simulations.
pref.dlg.checkbox.Runsimulations = Run out-dated simulations when you open the simulation tab.
pref.dlg.checkbox.Updateestimates = Update estimated flight parameters in design window
pref.dlg.checkbox.Markers = Only show pod set/booster markers when the pod set/booster is selected
pref.dlg.checkbox.Markers.ttip = <html>If checked, pod set/booster markers will only be shown when the pod set/booster is selected.<br>If unchecked, pod set/booster markers will always be shown.</html>
pref.dlg.checkbox.AlwaysOpenLeftmost = Always open leftmost tab when opening a component edit dialog
pref.dlg.checkbox.AlwaysOpenLeftmost.ttip = <html>If checked, a component edit dialog will always pop up with the first tab selected.<br>If unchecked, the previous selected tab will be used.</html>
pref.dlg.lbl.User-definedthrust = User-defined thrust curves:
@ -715,7 +717,7 @@ compaddbuttons.Launchlug = Launch Lug
compaddbuttons.RailButton = Rail Button
compaddbuttons.InnerComponent = Inner Components
compaddbuttons.Innertube = Inner Tube
compaddbuttons.Coupler = Coupler
compaddbuttons.Coupler = Tube Coupler
compaddbuttons.Centeringring = Centering\nRing
compaddbuttons.Bulkhead = Bulkhead
compaddbuttons.Engineblock = Engine\nBlock
@ -887,16 +889,17 @@ RocketCfg.lbl.Material = Material:
! RocketComponentConfig
RocketCompCfg.lbl.Componentname = Component name:
RocketCompCfg.ttip.Thecomponentname = The component name.
RocketCompCfg.lbl.Componentname.ttip = The component name.
RocketCompCfg.tab.Override = Override
RocketCompCfg.tab.MassandCGoverride = Mass and CG override options
RocketCompCfg.tab.Override.ttip = Mass and CG override options
RocketCompCfg.tab.Assembly = General
RocketCompCfg.tab.AssemblyComment = Options for locating stages parallel to other stages
RocketCompCfg.tab.Figure = Figure
RocketCompCfg.tab.Figstyleopt = Figure style options
RocketCompCfg.tab.Comment = Comment
RocketCompCfg.tab.Specifyacomment = Specify a comment for the component
RocketCompCfg.tab.Appearance = Appearance
RocketCompCfg.tab.Comment.ttip = Specify a comment for the component
RocketCompCfg.tab.Appearance = Appearance
RocketCompCfg.tab.Appearance.ttip = Component's appearance
RocketCompCfg.lbl.Mass = Mass:
RocketCompCfg.lbl.Componentmass = Component mass:
RocketCompCfg.lbl.overriddento = (overridden to
@ -2071,8 +2074,10 @@ CustomFinImport.error.badimage = Could not deduce fin shape from image.
CustomFinImport.description = The image will be converted internally to black and white image (black for the fin), so make sure you use a solid dark color for the fin, and white or a light color for the background. The fin must be touching the bottom of the image, which is the base of the fin.
PresetModel.lbl.select = Select preset
PresetModel.lbl.database = From database\u2026
PresetModel.combo.ttip = <html>Select a preset model from a list of favorites (selected in the component preset dialog),<br>or select 'Custom' when no preset is required.</html>
PresetModel.lbl.custompreset = Custom
PresetModel.lbl.partsLib = Parts Library
PresetModel.lbl.partsLib.ttip = Select a preset model for this rocket component from a library of parts.
DecalModel.lbl.select = <none>
DecalModel.lbl.choose = From file\u2026
@ -2094,7 +2099,7 @@ ComponentPresetChooserDialog.menu.sortDesc = Sort Descending
ComponentPresetChooserDialog.menu.units = Units
ComponentPresetChooserDialog.checkbox.showAllCompatible = Show all compatible
ComponentPresetChooserDialog.checkbox.showLegacyCheckBox = Show Legacy Database
ComponentPresetChooserDialog.lbl.favorites = Select to add preset to drop-down menu
ComponentPresetChooserDialog.lbl.favorites = Check to add preset to the preset drop-down menu in the component edit dialog
table.column.Favorite = Favorite
table.column.Legacy = Legacy
table.column.Manufacturer = Manufacturer

View File

@ -621,13 +621,13 @@ ShockCordCfg.lbl.Shockcordlength = D
! RocketComponentConfig
RocketCompCfg.lbl.Componentname = Jméno komponenty:
RocketCompCfg.ttip.Thecomponentname = Jméno komponenty.
RocketCompCfg.lbl.Componentname.ttip = Jméno komponenty.
RocketCompCfg.tab.Override = Prepsat
RocketCompCfg.tab.MassandCGoverride = Prepi\u0161 hmotnost a te\u017Ei\u0161te
RocketCompCfg.tab.Override.ttip = Prepi\u0161 hmotnost a te\u017Ei\u0161te
RocketCompCfg.tab.Figure = Obrázek
RocketCompCfg.tab.Figstyleopt = Vlastnosti obrázku
RocketCompCfg.tab.Comment = Komentár
RocketCompCfg.tab.Specifyacomment = Upresnení komentáre komponenty
RocketCompCfg.tab.Comment.ttip = Upresnení komentáre komponenty
RocketCompCfg.lbl.Mass = Hmotnost:
RocketCompCfg.lbl.Componentmass = Hmotnost komponenty:
RocketCompCfg.lbl.overriddento = (prepsáno na
@ -1587,8 +1587,8 @@ CustomFinImport.error.badimage = Nemohu vyvodit tvar stabiliz
CustomFinImport.description = Obrázek bude zmenen na cernobílý \n(cerná pro stabilizátor), ujistete se prosím, \u017Ee jste pou\u017Eily cernou barvu na stabilizátor \na bílou nebo svetlou barvu na pozadí. Stabilizátor \nse musí dotýkat steny obrázku, která predstavuje uchycení pro stabilizátor.
PresetModel.lbl.select = Výber predvolby:
PresetModel.lbl.database = Z databáze...
PresetModel.lbl.custompreset = Vlastní
PresetModel.lbl.partsLib = Knihovna díl?
! Component Preset Chooser Dialog

View File

@ -677,13 +677,13 @@ ShockCordCfg.lbl.Shockcordlength = Gummibandl
! RocketComponentConfig
RocketCompCfg.lbl.Componentname = Komponentenname:
RocketCompCfg.ttip.Thecomponentname = Name der Komponente.
RocketCompCfg.lbl.Componentname.ttip = Name der Komponente.
RocketCompCfg.tab.Override = Werte überschreiben
RocketCompCfg.tab.MassandCGoverride = Massen- und Schwerpunktsoptionen
RocketCompCfg.tab.Override.ttip = Massen- und Schwerpunktsoptionen
RocketCompCfg.tab.Figure = Form
RocketCompCfg.tab.Figstyleopt = Formoptionen
RocketCompCfg.tab.Comment = Kommentar
RocketCompCfg.tab.Specifyacomment = Kommentar zu dieser Komponente
RocketCompCfg.tab.Comment.ttip = Kommentar zu dieser Komponente
RocketCompCfg.lbl.Mass = Masse:
RocketCompCfg.lbl.Componentmass = Masse der Komponente:
RocketCompCfg.lbl.overriddento = (überschrieben auf
@ -1645,8 +1645,8 @@ CustomFinImport.error.badimage = Konnte keine Leitwerksform aus dem Bild erzeuge
CustomFinImport.description = Das Bild wird intern in ein Schwarz-Weiß-Bild konvertiert (Leitwerk: schwarz). Bitte sicherstellen, dass das Leitwerk in einer dichten, dunklen Farbe ist, während der Hintergrund weiß oder sehr hell sein sollte. Das Leitwerk muss das untere Bildende berühren, da dies die Verbindungsstelle zur Rakete wird.
PresetModel.lbl.select = Voreinstellung auswählen:
PresetModel.lbl.database = Aus Datenbank...
PresetModel.lbl.custompreset = Benutzerdefiniert
PresetModel.lbl.partsLib = Teile-Bibliothek
! Component Preset Chooser Dialog

View File

@ -737,8 +737,8 @@ PreferencesDialog.languages.default = Idioma por defecto
PreferencesDialog.lbl.language = Idioma de la interfaz:
PreferencesDialog.lbl.languageEffect = El idioma cambiar\u00e1 la pr\u00f3xima vez que abra OpenRocket.
PresetModel.lbl.database = Desde la Base de Datos...
PresetModel.lbl.select = Prefabricado
PresetModel.lbl.custompreset = Personalizado
PresetModel.lbl.partsLib = Biblioteca de piezas
PrintDialog.but.previewAndPrint = Vista previa e Imprimir
PrintDialog.checkbox.showByStage = Mostrar por etapas
@ -861,13 +861,13 @@ RocketCompCfg.tab.Appearance = Apariencia
RocketCompCfg.tab.Comment = Comentarios
RocketCompCfg.tab.Figstyleopt = Opciones de estilo de la figura
RocketCompCfg.tab.Figure = Estilo
RocketCompCfg.tab.MassandCGoverride = Especificar la Masa y el CG del componente.
RocketCompCfg.tab.Override.ttip = Especificar la Masa y el CG del componente.
RocketCompCfg.tab.Override = Masa y CG
RocketCompCfg.tab.Specifyacomment = Especifique un comentario para el componente
RocketCompCfg.tab.Comment.ttip = Especifique un comentario para el componente
RocketCompCfg.title.Aftshoulder = Trasera del acople
RocketCompCfg.title.Noseconeshoulder = Acople de la ojiva
RocketCompCfg.ttip.Endcapped = Si el extremo del soporte est\u00e1 truncado.
RocketCompCfg.ttip.Thecomponentname = El nombre del componente.
RocketCompCfg.lbl.Componentname.ttip = El nombre del componente.
RocketComponent.Position.ABSOLUTE = Extremo de la ojiva
RocketComponent.Position.AFTER = Despu\u00e9s del componente

View File

@ -729,8 +729,8 @@ PreferencesDialog.languages.default = Valeur syst\u00E8me par d\u00E9faut
PreferencesDialog.lbl.language = Langue du programme:
PreferencesDialog.lbl.languageEffect = La langue sera chang\u00E9e apr\u00E8s avoir red\u00E9marr\u00E9 OpenRocket.
PresetModel.lbl.database = A partir d'une base de donn\u00E9es...
PresetModel.lbl.select = Choisir une pi\u00E8ce pr\u00E9d\u00E9finie:
PresetModel.lbl.custompreset = Personnalisé
PresetModel.lbl.partsLib = Biblioth\u00E8que de pi\u00E8ces
PrintDialog.but.previewAndPrint = Pr\u00E9-visualiser et imprimer
PrintDialog.checkbox.showByStage = Montrer par \u00E9tage
@ -853,13 +853,13 @@ RocketCompCfg.tab.Appearance = Apparence
RocketCompCfg.tab.Comment = Commentaires
RocketCompCfg.tab.Figstyleopt = Options de la forme
RocketCompCfg.tab.Figure = Forme
RocketCompCfg.tab.MassandCGoverride = For\u00E7age de la Masse et du CG
RocketCompCfg.tab.Override.ttip = For\u00E7age de la Masse et du CG
RocketCompCfg.tab.Override = Forcer la valeur
RocketCompCfg.tab.Specifyacomment = Commentaires concernant la pi\u00E8ce
RocketCompCfg.tab.Comment.ttip = Commentaires concernant la pi\u00E8ce
RocketCompCfg.title.Aftshoulder = Epaulement arri\u00E8re
RocketCompCfg.title.Noseconeshoulder = Epaulement du c\u00F4ne
RocketCompCfg.ttip.Endcapped = Pr\u00E9cise si l'arri\u00E8re du c\u00F4ne est clos.
RocketCompCfg.ttip.Thecomponentname = Le nom de la pi\u00E8ce.
RocketCompCfg.lbl.Componentname.ttip = Le nom de la pi\u00E8ce.
RocketComponent.Position.ABSOLUTE = Pointe de l'ogive
RocketComponent.Position.AFTER = Apr\u00E8s la pi\u00E8ce parente

View File

@ -679,13 +679,13 @@ ShockCordCfg.lbl.Shockcordlength = Lunghezza della Shock cord :
! RocketComponentConfig
RocketCompCfg.lbl.Componentname = Nome componente:
RocketCompCfg.ttip.Thecomponentname = Il nome del componente.
RocketCompCfg.lbl.Componentname.ttip = Il nome del componente.
RocketCompCfg.tab.Override = Modifica
RocketCompCfg.tab.MassandCGoverride = Opzioni di sovrascrittura di massa e CG
RocketCompCfg.tab.Override.ttip = Opzioni di sovrascrittura di massa e CG
RocketCompCfg.tab.Figure = Disegno
RocketCompCfg.tab.Figstyleopt = Opzioni dello stile della figure
RocketCompCfg.tab.Comment = Commento
RocketCompCfg.tab.Specifyacomment = Specifica un commento per il componente
RocketCompCfg.tab.Comment.ttip = Specifica un commento per il componente
RocketCompCfg.lbl.Mass = Massa:
RocketCompCfg.lbl.Componentmass = La massa del componente :
RocketCompCfg.lbl.overriddento = (sovrascritto a
@ -1651,8 +1651,8 @@ CustomFinImport.error.badimage = Non riesco a capire la forma della pinna dall
CustomFinImport.description = L'immagine sar\u00e0 convertita in bianco e nero internamente (nero per le pinne), cos\u00ec assicurati di usare un nero pieno per le pinne e bianco, o colore chiaro, per lo sfondo. La pinna ndeve toccare il fondo dell'immagine, che \u00e8 la base della pinna.
PresetModel.lbl.select = Seleziona precaricati:
PresetModel.lbl.database = Da database...
PresetModel.lbl.custompreset = Personalizzato
PresetModel.lbl.partsLib = Libreria di parti
! Component Preset Chooser Dialog

View File

@ -709,13 +709,13 @@ ShockCordCfg.lbl.Shockcordlength = \u30B7\u30E7\u30C3\u30AF\u30B3\u30FC\u30C9\u
! RocketComponentConfig
RocketCompCfg.lbl.Componentname = \u90E8\u54C1\u540D\uFF1A
RocketCompCfg.ttip.Thecomponentname = \u90E8\u54C1\u306E\u540D\u524D
RocketCompCfg.lbl.Componentname.ttip = \u90E8\u54C1\u306E\u540D\u524D
RocketCompCfg.tab.Override = \u518D\u5B9A\u7FA9
RocketCompCfg.tab.MassandCGoverride = \u8CEA\u91CF\u3068CG\u3092\u518D\u5B9A\u7FA9\u3059\u308B\u30AA\u30D7\u30B7\u30E7\u30F3
RocketCompCfg.tab.Override.ttip = \u8CEA\u91CF\u3068CG\u3092\u518D\u5B9A\u7FA9\u3059\u308B\u30AA\u30D7\u30B7\u30E7\u30F3
RocketCompCfg.tab.Figure = \u56F3\u793A
RocketCompCfg.tab.Figstyleopt = \u56F3\u793A\u306E\u30B9\u30BF\u30A4\u30EB\u30AA\u30D7\u30B7\u30E7\u30F3
RocketCompCfg.tab.Comment = \u30B3\u30E1\u30F3\u30C8
RocketCompCfg.tab.Specifyacomment = \u90E8\u54C1\u3078\u306E\u30B3\u30E1\u30F3\u30C8\u3092\u8A18\u8FF0
RocketCompCfg.tab.Comment.ttip = \u90E8\u54C1\u3078\u306E\u30B3\u30E1\u30F3\u30C8\u3092\u8A18\u8FF0
RocketCompCfg.lbl.Mass = \u8CEA\u91CF\uFF1A
RocketCompCfg.lbl.Componentmass = \u90E8\u54C1\u8CEA\u91CF\uFF1A
RocketCompCfg.lbl.overriddento = (overridden to
@ -1713,8 +1713,8 @@ CustomFinImport.error.badimage = \u753B\u50CF\u304B\u3089\u30D5\u30A3\u30F3\u5F
CustomFinImport.description = \u753B\u50CF\u306F\u5185\u90E8\u3067\u767D\u80CC\u666F\u3068\u9ED2\u7DDA\u306B\u5909\u63DB\u3055\u308C\u307E\u3059\u3002\u306A\u306E\u3067\u30D5\u30A3\u30F3\u306B\u306F\u6697\u3044\u8272\u306E\u5B9F\u7DDA\u3001\u80CC\u666F\u306B\u306F\u767D\u304B\u660E\u308B\u3044\u8272\u3092\u4F7F\u7528\u3057\u3066\u304F\u3060\u3055\u3044\u3002\u30D5\u30A3\u30F3\u306F\u753B\u50CF\u306E\u5E95\u9762\u306B\u63A5\u3057\u3066\u3044\u306A\u304F\u3066\u306F\u3044\u3051\u307E\u305B\u3093\u3001\u3053\u308C\u306F\u30D5\u30A3\u30F3\u306E\u5E95\u9762\u306B\u306A\u308A\u307E\u3059\u3002
PresetModel.lbl.select = Select preset
PresetModel.lbl.database = From database...
PresetModel.lbl.custompreset = \u30ab\u30b9\u30bf\u30e0
PresetModel.lbl.partsLib = \u30d1\u30fc\u30c4\u30e9\u30a4\u30d6\u30e9\u30ea\u30fc
! Component Preset Chooser Dialog

View File

@ -826,15 +826,15 @@ RocketCfg.lbl.Material = Materiaal:
! RocketComponentConfig
RocketCompCfg.lbl.Componentname = Componentnaam:
RocketCompCfg.ttip.Thecomponentname = De componentnaam.
RocketCompCfg.lbl.Componentname.ttip = De componentnaam.
RocketCompCfg.tab.Override = Overschrijf
RocketCompCfg.tab.MassandCGoverride = Massa en ZP overschrijvingsopties
RocketCompCfg.tab.Override.ttip = Massa en ZP overschrijvingsopties
RocketCompCfg.tab.Assembly = Algemeen
RocketCompCfg.tab.AssemblyComment = Opties voor het plaatsen van trappen parallel aan andere trappen
RocketCompCfg.tab.Figure = Figuur
RocketCompCfg.tab.Figstyleopt = Figuurstijl opties
RocketCompCfg.tab.Comment = Opmerking
RocketCompCfg.tab.Specifyacomment = Geef een opmerking voor het onderdeel
RocketCompCfg.tab.Comment.ttip = Geef een opmerking voor het onderdeel
RocketCompCfg.tab.Appearance = Uiterlijk
RocketCompCfg.lbl.Mass = Massa:
RocketCompCfg.lbl.Componentmass = Componentmassa:
@ -1967,8 +1967,8 @@ CustomFinImport.error.badimage = Kon de vorm van de vin niet afleiden uit het be
CustomFinImport.description = De afbeelding wordt intern geconverteerd naar een zwart-wit afbeelding (zwart voor de vin), dus zorg ervoor dat je een effen donkere kleur gebruikt voor de vin, en wit of een lichte kleur voor de achtergrond. De vin moet de onderkant van het beeld raken, dat is de basis van de vin.
PresetModel.lbl.select = Selecteer preset
PresetModel.lbl.database = Uit databank...
PresetModel.lbl.custompreset = Aangepast
PresetModel.lbl.partsLib = Onderdelenbibliotheek
DecalModel.lbl.select = <geen>
DecalModel.lbl.choose = Van bestand...

View File

@ -623,13 +623,13 @@ update.dlg.latestVersion = Korzystasz z najnowszej wersji OpenRocket: %s.
! RocketComponentConfig
RocketCompCfg.lbl.Componentname = Nazwa cz\u0119\u015Bci:
RocketCompCfg.ttip.Thecomponentname = Nazwa cz\u0119\u015Bci sk\u0142adowej rakiety.
RocketCompCfg.lbl.Componentname.ttip = Nazwa cz\u0119\u015Bci sk\u0142adowej rakiety.
RocketCompCfg.tab.Override = Wymu\u015B
RocketCompCfg.tab.MassandCGoverride = Opcje wymuszenia ci\u0119\u017Caru oraz \u015Brodka ci\u0119\u017Cko\u015Bci
RocketCompCfg.tab.Override.ttip = Opcje wymuszenia ci\u0119\u017Caru oraz \u015Brodka ci\u0119\u017Cko\u015Bci
RocketCompCfg.tab.Figure = Wygl\u0105d
RocketCompCfg.tab.Figstyleopt = Styl kszta\u0142tu
RocketCompCfg.tab.Comment = Uwagi
RocketCompCfg.tab.Specifyacomment = Dodaj uwagi do cz\u0119\u015Bci
RocketCompCfg.tab.Comment.ttip = Dodaj uwagi do cz\u0119\u015Bci
RocketCompCfg.lbl.Mass = Masa:
RocketCompCfg.lbl.Componentmass = Masa cz\u0119\u015Bci:
RocketCompCfg.lbl.overriddento = (wymuszone do
@ -1592,8 +1592,8 @@ update.dlg.latestVersion = Korzystasz z najnowszej wersji OpenRocket: %s.
CustomFinImport.description = Obraz zostanie automatycznie zamieniony na czarno-bia\u0142y (statecznik w kolorze czarnym), wi\u0119c upewnij si\u0119, \u017Ce kszta\u0142t statecznika jest wype\u0142niony ciemnym kolorem, a t\u0142o jest bia\u0142e lub jasne. Podstawa statecznika musi przylega\u0107 do dolnej kraw\u0119dzi obrazu.
PresetModel.lbl.select = Wybierz ustawienia:
PresetModel.lbl.database = Z bazy danych...
PresetModel.lbl.custompreset = Niestandardowe
PresetModel.lbl.partsLib = Biblioteka cz??ci
! Component Preset Chooser Dialog

View File

@ -715,8 +715,8 @@ PreferencesDialog.languages.default = Padr\u00e3o do sistema
PreferencesDialog.lbl.language = Idioma da interface:
PreferencesDialog.lbl.languageEffect = A linguagem vai mudar na pr\u00f3xima vez que voc\u00ea iniciar o OpenRocket.
PresetModel.lbl.database = \u00c0 partir do banco de dados...
PresetModel.lbl.select = Selecione ajustes pr\u00e9-definidos
PresetModel.lbl.custompreset = Personalizado
PresetModel.lbl.partsLib = Biblioteca de pe\u00e7as
PrintDialog.but.previewAndPrint = Visualiza\u00e7\u00e3o e impress\u00e3o
PrintDialog.checkbox.showByStage = Mostrar por est\u00e1gio
@ -838,13 +838,13 @@ RocketCompCfg.lbl.ttip.componentmaterialaffects = O material do componente afe
RocketCompCfg.tab.Comment = Coment\u00e1rio
RocketCompCfg.tab.Figstyleopt = Op\u00e7\u00f5es do estilo de figura
RocketCompCfg.tab.Figure = Figura
RocketCompCfg.tab.MassandCGoverride = Op\u00e7\u00f5es de modifica\u00e7\u00e3o de massa e CG
RocketCompCfg.tab.Override.ttip = Op\u00e7\u00f5es de modifica\u00e7\u00e3o de massa e CG
RocketCompCfg.tab.Override = Modificar
RocketCompCfg.tab.Specifyacomment = Especifique um coment\u00e1rio para o componente
RocketCompCfg.tab.Comment.ttip = Especifique um coment\u00e1rio para o componente
RocketCompCfg.title.Aftshoulder = Ressalto traseiro
RocketCompCfg.title.Noseconeshoulder = Ressalto da ogiva
RocketCompCfg.ttip.Endcapped = Quando a extremidade do ressalto \u00e9 limitada.
RocketCompCfg.ttip.Thecomponentname = Nome do componente.
RocketCompCfg.lbl.Componentname.ttip = Nome do componente.
RocketComponent.Position.ABSOLUTE = Dica da ogiva
RocketComponent.Position.AFTER = Depois do componente pai

View File

@ -888,15 +888,15 @@ RocketCfg.lbl.Material = \u041C\u0430\u0442\u0435\u0440\u0438\u0430\u043B:
! RocketComponentConfig
RocketCompCfg.lbl.Componentname = \u041D\u0430\u0437\u0432\u0430\u043D\u0438\u0435 \u043A\u043E\u043C\u043F\u043E\u043D\u0435\u043D\u0442\u0430:
RocketCompCfg.ttip.Thecomponentname = \u041D\u0430\u0437\u0432\u0430\u043D\u0438\u0435 \u043A\u043E\u043C\u043F\u043E\u043D\u0435\u043D\u0442\u0430.
RocketCompCfg.lbl.Componentname.ttip = \u041D\u0430\u0437\u0432\u0430\u043D\u0438\u0435 \u043A\u043E\u043C\u043F\u043E\u043D\u0435\u043D\u0442\u0430.
RocketCompCfg.tab.Override = \u041F\u0435\u0440\u0435\u043E\u043F\u0440\u0435\u0434\u0435\u043B\u0435\u043D\u0438\u0435
RocketCompCfg.tab.MassandCGoverride = \u041F\u0435\u0440\u0435\u043E\u043F\u0440\u0435\u0434\u0435\u043B\u0435\u043D\u0438\u0435 \u043C\u0430\u0441\u0441\u044B \u0438 \u0426\u0422
RocketCompCfg.tab.Override.ttip = \u041F\u0435\u0440\u0435\u043E\u043F\u0440\u0435\u0434\u0435\u043B\u0435\u043D\u0438\u0435 \u043C\u0430\u0441\u0441\u044B \u0438 \u0426\u0422
RocketCompCfg.tab.Assembly = \u0421\u0431\u043E\u0440\u043A\u0430
RocketCompCfg.tab.AssemblyComment = \u041F\u0430\u0440\u0430\u043C\u0435\u0442\u0440\u044B \u0440\u0430\u0437\u043C\u0435\u0449\u0435\u043D\u0438\u044F \u0441\u0442\u0443\u043F\u0435\u043D\u0435\u0439 \u043F\u0430\u0440\u0430\u043B\u043B\u0435\u043B\u044C\u043D\u043E \u0434\u0440\u0443\u0433\u0438\u043C \u0441\u0442\u0443\u043F\u0435\u043D\u044F\u043C
RocketCompCfg.tab.Figure = \u0420\u0438\u0441\u0443\u043D\u043E\u043A
RocketCompCfg.tab.Figstyleopt = \u041F\u0430\u0440\u0430\u043C\u0435\u0442\u0440\u044B \u0441\u0442\u0438\u043B\u044F \u0440\u0438\u0441\u0443\u043D\u043A\u0430
RocketCompCfg.tab.Comment = \u041F\u0440\u0438\u043C\u0435\u0447\u0430\u043D\u0438\u0435
RocketCompCfg.tab.Specifyacomment = \u0423\u043A\u0430\u0436\u0438\u0442\u0435 \u043F\u0440\u0438\u043C\u0435\u0447\u0430\u043D\u0438\u0435 \u043A \u043A\u043E\u043C\u043F\u043E\u043D\u0435\u043D\u0442\u0443
RocketCompCfg.tab.Comment.ttip = \u0423\u043A\u0430\u0436\u0438\u0442\u0435 \u043F\u0440\u0438\u043C\u0435\u0447\u0430\u043D\u0438\u0435 \u043A \u043A\u043E\u043C\u043F\u043E\u043D\u0435\u043D\u0442\u0443
RocketCompCfg.tab.Appearance = \u0412\u043D\u0435\u0448\u043D\u0438\u0439 \u0432\u0438\u0434
RocketCompCfg.lbl.Mass = \u041C\u0430\u0441\u0441\u0430:
RocketCompCfg.lbl.Componentmass = \u041C\u0430\u0441\u0441\u0430 \u043A\u043E\u043C\u043F\u043E\u043D\u0435\u043D\u0442\u0430:
@ -2075,8 +2075,8 @@ CustomFinImport.error.badimage = \u041D\u0435\u0432\u043E\u0437\u043C\u043E\u043
CustomFinImport.description = \u0418\u0437\u043E\u0431\u0440\u0430\u0436\u0435\u043D\u0438\u0435 \u043F\u0440\u0435\u043E\u0431\u0440\u0430\u0437\u0443\u0435\u0442\u0441\u044F \u0432 \u0447\u0435\u0440\u043D\u043E-\u0431\u0435\u043B\u043E\u0435 (\u0433\u0434\u0435 \u0447\u0435\u0440\u043D\u044B\u0439 - \u0446\u0432\u0435\u0442 \u0441\u0442\u0430\u0431\u0438\u043B\u0438\u0437\u0430\u0442\u043E\u0440\u0430), \u0442\u0430\u043A \u0447\u0442\u043E \u0438\u0441\u043F\u043E\u043B\u044C\u0437\u0443\u0439\u0442\u0435 \u0447\u0435\u0440\u043D\u044B\u0439 \u0446\u0432\u0435\u0442 \u0434\u043B\u044F \u0440\u0438\u0441\u0443\u043D\u043A\u0430 \u0441\u0442\u0430\u0431\u0438\u043B\u0438\u0437\u0430\u0442\u043E\u0440\u0430 \u0438 \u0431\u0435\u043B\u044B\u0439 \u0438\u043B\u0438 \u0441\u0432\u0435\u0442\u043B\u044B\u0439 \u0446\u0432\u0435\u0442 \u0434\u043B\u044F \u0444\u043E\u043D\u0430. \u041E\u0441\u043D\u043E\u0432\u0430\u043D\u0438\u0435 \u0441\u0442\u0430\u0431\u0438\u043B\u0438\u0437\u0430\u0442\u043E\u0440\u0430 \u0434\u043E\u043B\u0436\u043D\u043E \u043D\u0430\u0447\u0438\u043D\u0430\u0442\u044C\u0441\u044F \u0441\u043D\u0438\u0437\u0443 \u0438\u0437\u043E\u0431\u0440\u0430\u0436\u0435\u043D\u0438\u044F.
PresetModel.lbl.select = \u0412\u044B\u0431\u0435\u0440\u0438\u0442\u0435 \u0437\u0430\u0433\u043E\u0442\u043E\u0432\u043A\u0443
PresetModel.lbl.database = \u0418\u0437 \u0431\u0430\u0437\u044B \u0434\u0430\u043D\u043D\u044B\u0445...
PresetModel.lbl.custompreset = \u0411\u0438\u0431\u043b\u0438\u043e\u0442\u0435\u043a\u0430\u0020\u0434\u0435\u0442\u0430\u043b\u0435\u0439
PresetModel.lbl.partsLib = \u0411\u0438\u0431\u043b\u0438\u043e\u0442\u0435\u043a\u0430\u0020\u0434\u0435\u0442\u0430\u043b\u0435\u0439
DecalModel.lbl.select = <\u043D\u0435\u0442>
DecalModel.lbl.choose = \u0418\u0437 \u0444\u0430\u0439\u043B\u0430...

View File

@ -779,13 +779,13 @@ ShockCordCfg.lbl.Shockcordlength = Shock cord length:
! RocketComponentConfig
RocketCompCfg.lbl.Componentname = Component name:
RocketCompCfg.ttip.Thecomponentname = The component name.
RocketCompCfg.lbl.Componentname.ttip = The component name.
RocketCompCfg.tab.Override = Override
RocketCompCfg.tab.MassandCGoverride = Mass and CG override options
RocketCompCfg.tab.Override.ttip = Mass and CG override options
RocketCompCfg.tab.Figure = Figure
RocketCompCfg.tab.Figstyleopt = Figure style options
RocketCompCfg.tab.Comment = Comment
RocketCompCfg.tab.Specifyacomment = Specify a comment for the component
RocketCompCfg.tab.Comment.ttip = Specify a comment for the component
RocketCompCfg.tab.Appearance = Appearance
RocketCompCfg.lbl.Mass = Mass:
RocketCompCfg.lbl.Componentmass = Component mass:
@ -1812,8 +1812,8 @@ CustomFinImport.error.badimage = Could not deduce fin shape from image.
CustomFinImport.description = The image will be converted internally to black and white image (black for the fin), so make sure you use a solid dark color for the fin, and white or a light color for the background. The fin must be touching the bottom of the image, which is the base of the fin.
PresetModel.lbl.select = Select preset
PresetModel.lbl.database = From database...
PresetModel.lbl.custompreset = Custom
PresetModel.lbl.partsLib = Parts Library
DecalModel.lbl.select = <none>
DecalModel.lbl.choose = From file...

View File

@ -803,8 +803,8 @@ PreferencesDialog.languages.default = \u7CFB\u7EDF\u9ED8\u8BA4
PreferencesDialog.lbl.language = \u754C\u9762\u8BED\u8A00:
PreferencesDialog.lbl.languageEffect = \u8BED\u8A00\u8BBE\u7F6E\u5C06\u5728OpenRocket\u91CD\u542F\u540E\u751F\u6548
PresetModel.lbl.database = \u4ECE\u6570\u636E\u5E93...
PresetModel.lbl.select = \u9009\u62E9\u9884\u8BBE
PresetModel.lbl.custompreset = \u5b9a\u5236
PresetModel.lbl.partsLib = \u96f6\u4ef6\u5e93
PrintDialog.but.previewAndPrint = \u9884\u89C8 & \u6253\u5370
PrintDialog.checkbox.showByStage = \u6309\u7EA7\u663E\u793A
@ -927,13 +927,13 @@ RocketCompCfg.tab.Appearance = \u5916\u89C2
RocketCompCfg.tab.Comment = \u6CE8\u91CA
RocketCompCfg.tab.Figstyleopt = \u6837\u5F0F\u9009\u9879
RocketCompCfg.tab.Figure = \u6837\u5F0F
RocketCompCfg.tab.MassandCGoverride = \u8D28\u91CF\u53CA\u91CD\u5FC3\u9009\u9879
RocketCompCfg.tab.Override.ttip = \u8D28\u91CF\u53CA\u91CD\u5FC3\u9009\u9879
RocketCompCfg.tab.Override = \u8986\u5199
RocketCompCfg.tab.Specifyacomment = \u7EC4\u4EF6\u6CE8\u91CA
RocketCompCfg.tab.Comment.ttip = \u7EC4\u4EF6\u6CE8\u91CA
RocketCompCfg.title.Aftshoulder = \u524D\u8FDE\u63A5\u5904
RocketCompCfg.title.Noseconeshoulder = \u5934\u9525\u8FDE\u63A5\u5904
RocketCompCfg.ttip.Endcapped = \u8FDE\u63A5\u5904\u7EC8\u7AEF\u662F\u5426\u6709\u76D6.
RocketCompCfg.ttip.Thecomponentname = \u7EC4\u4EF6\u540D\u79F0.
RocketCompCfg.lbl.Componentname.ttip = \u7EC4\u4EF6\u540D\u79F0.
RocketComponent.Position.ABSOLUTE = \u5934\u9525\u5C16\u7AEF
RocketComponent.Position.AFTER = \u7236\u7EC4\u4EF6\u4E4B\u540E

View File

@ -68,5 +68,5 @@ public interface AerodynamicCalculator extends Monitorable {
*/
public AerodynamicCalculator newInstance();
public boolean isContinuous( final Rocket rkt);
public boolean isContinuous(FlightConfiguration configuration, final Rocket rkt);
}

View File

@ -4,6 +4,7 @@ import static net.sf.openrocket.util.MathUtil.pow2;
import java.util.*;
import net.sf.openrocket.rocketcomponent.AxialStage;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@ -80,7 +81,7 @@ public class BarrowmanCalculator extends AbstractAerodynamicCalculator {
Map<RocketComponent, AerodynamicForces> assemblyMap = new LinkedHashMap<>();
// Calculate non-axial force data
calculateForceAnalysis(conditions, configuration.getRocket(), instMap, eachMap, assemblyMap, warnings);
calculateForceAnalysis(configuration, conditions, configuration.getRocket(), instMap, eachMap, assemblyMap, warnings);
// Calculate drag coefficient data
AerodynamicForces rocketForces = assemblyMap.get(configuration.getRocket());
@ -125,7 +126,8 @@ public class BarrowmanCalculator extends AbstractAerodynamicCalculator {
return finalMap;
}
private AerodynamicForces calculateForceAnalysis( FlightConditions conds,
private AerodynamicForces calculateForceAnalysis( FlightConfiguration configuration,
FlightConditions conds,
RocketComponent comp,
InstanceMap instances,
Map<RocketComponent, AerodynamicForces> eachForces,
@ -152,8 +154,12 @@ public class BarrowmanCalculator extends AbstractAerodynamicCalculator {
}
for( RocketComponent child : comp.getChildren()) {
// Ignore inactive stages
if (child instanceof AxialStage && !configuration.isStageActive(child.getStageNumber())) {
continue;
}
// forces particular to each component
AerodynamicForces childForces = calculateForceAnalysis(conds, child, instances, eachForces, assemblyForces, warnings);
AerodynamicForces childForces = calculateForceAnalysis(configuration, conds, child, instances, eachForces, assemblyForces, warnings);
if(null != childForces) {
aggregateForces.merge(childForces);
@ -240,7 +246,7 @@ public class BarrowmanCalculator extends AbstractAerodynamicCalculator {
if (calcMap == null)
buildCalcMap(configuration);
if( ! isContinuous( configuration.getRocket() ) ){
if (!isContinuous(configuration, configuration.getRocket())){
warnings.add( Warning.DIAMETER_DISCONTINUITY);
}
@ -266,20 +272,32 @@ public class BarrowmanCalculator extends AbstractAerodynamicCalculator {
}
@Override
public boolean isContinuous( final Rocket rkt){
return testIsContinuous( rkt);
public boolean isContinuous(FlightConfiguration configuration, final Rocket rkt){
return testIsContinuous(configuration, rkt);
}
private boolean testIsContinuous( final RocketComponent treeRoot ){
private boolean testIsContinuous(FlightConfiguration configuration, final RocketComponent treeRoot ){
Queue<RocketComponent> queue = new LinkedList<>();
queue.addAll(treeRoot.getChildren());
for (RocketComponent child : treeRoot.getChildren()) {
// Ignore inactive stages
if (child instanceof AxialStage && !configuration.isStageActive(child.getStageNumber())) {
continue;
}
queue.add(child);
}
boolean isContinuous = true;
SymmetricComponent prevComp = null;
while((isContinuous)&&( null != queue.peek())){
RocketComponent comp = queue.poll();
if( comp instanceof SymmetricComponent ){
queue.addAll( comp.getChildren());
for (RocketComponent child : comp.getChildren()) {
// Ignore inactive stages
if (child instanceof AxialStage && !configuration.isStageActive(child.getStageNumber())) {
continue;
}
queue.add(child);
}
SymmetricComponent sym = (SymmetricComponent) comp;
if( null == prevComp){
@ -303,7 +321,7 @@ public class BarrowmanCalculator extends AbstractAerodynamicCalculator {
prevComp = sym;
}else if( comp instanceof ComponentAssembly ){
isContinuous &= testIsContinuous( comp );
isContinuous &= testIsContinuous(configuration, comp);
}
}
@ -319,7 +337,7 @@ public class BarrowmanCalculator extends AbstractAerodynamicCalculator {
* @param configuration Rocket configuration
* @param conditions Flight conditions taken into account
* @param map ?
* @param set Set to handle
* @param warningSet Set to handle warnings
* @return friction drag for entire rocket
*/
private double calculateFrictionCD(FlightConfiguration configuration, FlightConditions conditions,
@ -611,7 +629,7 @@ public class BarrowmanCalculator extends AbstractAerodynamicCalculator {
double radius = 0;
final SymmetricComponent prevComponent = s.getPreviousSymmetricComponent();
if (prevComponent != null)
if (prevComponent != null && configuration.isComponentActive(prevComponent))
radius = prevComponent.getAftRadius();
if (radius < s.getForeRadius()) {
@ -672,7 +690,7 @@ public class BarrowmanCalculator extends AbstractAerodynamicCalculator {
// its aft CD
double radius = 0;
final SymmetricComponent prevComponent = s.getPreviousSymmetricComponent();
if (prevComponent != null) {
if (prevComponent != null && configuration.isComponentActive(prevComponent)) {
radius = prevComponent.getAftRadius();
}

View File

@ -1,5 +1,6 @@
package net.sf.openrocket.document;
import java.lang.reflect.InvocationTargetException;
import java.util.EventListener;
import java.util.EventObject;
import java.util.List;
@ -350,13 +351,15 @@ public class Simulation implements ChangeSource, Cloneable {
SimulationEngine simulator;
try {
simulator = simulationEngineClass.newInstance();
simulator = simulationEngineClass.getConstructor().newInstance();
} catch (InstantiationException e) {
throw new IllegalStateException("Cannot instantiate simulator.", e);
} catch (IllegalAccessException e) {
throw new IllegalStateException("Cannot access simulator instance?! BUG!", e);
} catch (InvocationTargetException | NoSuchMethodException e) {
throw new RuntimeException(e);
}
SimulationConditions simulationConditions = options.toSimulationConditions();
simulationConditions.setSimulation(this);
for (SimulationListener l : additionalListeners) {

View File

@ -11,6 +11,9 @@ import org.xml.sax.SAXException;
import org.xml.sax.XMLReader;
import org.xml.sax.helpers.XMLReaderFactory;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.parsers.SAXParser;
import javax.xml.parsers.SAXParserFactory;
/**
* A "simple SAX" XML reader. This system imposes the limit that an XML element may
@ -18,27 +21,26 @@ import org.xml.sax.helpers.XMLReaderFactory;
* both. This holds true for both the OpenRocket and RockSim design formats and the
* RockSim engine definition format.
* <p>
* The actual handling is performed by subclasses of {@link ElementHandler}. The
* The actual handling is performed by subclasses of {@link ElementHandler}. The
* initial handler is provided to the {@link #readXML(InputSource, ElementHandler, WarningSet)}
* method.
*
*
* @author Sampo Niskanen <sampo.niskanen@iki.fi>
*/
public class SimpleSAX {
static final XMLReaderCache cache = new XMLReaderCache(10);
/**
* Read a simple XML file.
*
*
* @param source the SAX input source.
* @param initialHandler the initial content handler.
* @param warnings a warning set to store warning (cannot be <code>null</code>).
* @throws IOException if an I/O exception occurs while reading.
* @throws SAXException if e.g. malformed XML is encountered.
*/
public static void readXML(InputSource source, ElementHandler initialHandler,
WarningSet warnings) throws IOException, SAXException {
public static void readXML(InputSource source, ElementHandler initialHandler, WarningSet warnings)
throws IOException, SAXException {
DelegatorHandler xmlhandler = new DelegatorHandler(initialHandler, warnings);
@ -55,17 +57,27 @@ public class SimpleSAX {
}
private static class XMLReaderCache {
private final SAXParserFactory parserFactory;
private final BlockingQueue<XMLReader> queue;
private XMLReaderCache( int maxSize ) {
this.queue = new LinkedBlockingQueue<XMLReader>(maxSize);
parserFactory = SAXParserFactory.newInstance();
parserFactory.setNamespaceAware(true);
queue = new LinkedBlockingQueue<XMLReader>(maxSize);
}
private XMLReader createXMLReader() throws SAXException {
XMLReader reader = queue.poll();
if ( reader == null ) {
try {
reader = XMLReaderFactory.createXMLReader();
SAXParser parser = parserFactory.newSAXParser();
reader = parser.getXMLReader();
}
catch (ParserConfigurationException ignore) {
System.out.print(ignore);
}
}
return reader;
}
@ -77,5 +89,4 @@ public class SimpleSAX {
queue.offer( reader );
}
}
}

View File

@ -104,7 +104,7 @@ public class MassCalculator implements Monitorable {
public static RigidBody calculate( final MassCalculation.Type _type, final SimulationStatus status ){
final FlightConfiguration config = status.getConfiguration();
final double time = status.getSimulationTime();
final Collection<MotorClusterState> activeMotorList = status.getMotors();
final Collection<MotorClusterState> activeMotorList = status.getActiveMotors();
MassCalculation calculation= new MassCalculation( _type, config, time, activeMotorList, config.getRocket(), Transformation.IDENTITY, null);
calculation.calculateAssembly();

View File

@ -4,6 +4,7 @@ import java.util.Locale;
import net.sf.openrocket.l10n.Translator;
import net.sf.openrocket.rocketcomponent.AxialStage;
import net.sf.openrocket.rocketcomponent.FlightConfiguration;
import net.sf.openrocket.rocketcomponent.RocketComponent;
import net.sf.openrocket.simulation.FlightEvent;
import net.sf.openrocket.startup.Application;
@ -13,25 +14,25 @@ public enum IgnitionEvent {
//// Automatic (launch or ejection charge)
AUTOMATIC( "AUTOMATIC", "MotorMount.IgnitionEvent.AUTOMATIC"){
@Override
public boolean isActivationEvent(FlightEvent testEvent, RocketComponent targetComponent) {
public boolean isActivationEvent(FlightConfiguration config, FlightEvent testEvent, RocketComponent targetComponent) {
AxialStage targetStage = targetComponent.getStage();
if ( targetStage.isLaunchStage() ){
return LAUNCH.isActivationEvent(testEvent, targetComponent);
if (targetStage.isLaunchStage(config)) {
return LAUNCH.isActivationEvent(config, testEvent, targetComponent);
} else {
return EJECTION_CHARGE.isActivationEvent(testEvent, targetComponent);
return EJECTION_CHARGE.isActivationEvent(config, testEvent, targetComponent);
}
}
},
LAUNCH ( "LAUNCH", "MotorMount.IgnitionEvent.LAUNCH"){
@Override
public boolean isActivationEvent( FlightEvent fe, RocketComponent source){
public boolean isActivationEvent(FlightConfiguration config, FlightEvent fe, RocketComponent source){
return (fe.getType() == FlightEvent.Type.LAUNCH);
}
},
EJECTION_CHARGE ("EJECTION_CHARGE", "MotorMount.IgnitionEvent.EJECTION_CHARGE"){
@Override
public boolean isActivationEvent( FlightEvent testEvent, RocketComponent targetComponent){
public boolean isActivationEvent(FlightConfiguration config, FlightEvent testEvent, RocketComponent targetComponent){
if (testEvent.getType() != FlightEvent.Type.EJECTION_CHARGE){
return false;
}
@ -44,7 +45,7 @@ public enum IgnitionEvent {
},
BURNOUT ("BURNOUT", "MotorMount.IgnitionEvent.BURNOUT"){
@Override
public boolean isActivationEvent( FlightEvent testEvent, RocketComponent targetComponent){
public boolean isActivationEvent(FlightConfiguration config, FlightEvent testEvent, RocketComponent targetComponent){
if (testEvent.getType() != FlightEvent.Type.BURNOUT)
return false;
@ -64,7 +65,7 @@ public enum IgnitionEvent {
//public static final IgnitionEvent[] events = {AUTOMATIC, LAUNCH, EJECTION_CHARGE, BURNOUT, NEVER};
public boolean isActivationEvent( FlightEvent fe, RocketComponent source){
public boolean isActivationEvent(FlightConfiguration config, FlightEvent fe, RocketComponent source){
// default behavior. Also for the NEVER case.
return false;
}

View File

@ -67,6 +67,23 @@ public class AxialStage extends ComponentAssembly implements FlightConfigurableC
public boolean isCompatible(Class<? extends RocketComponent> type) {
return BodyComponent.class.isAssignableFrom(type);
}
/**
* Returns whether the current stage is active in the currently selected configuration.
* @return true if the stage is active, false if not
*/
public boolean isStageActive() {
return getRocket().getSelectedConfiguration().isStageActive(getStageNumber());
}
/**
* Returns whether the current stage is active in the flight configuration.
* @param fc the flight configuration to check
* @return true if the stage is active, false if not
*/
public boolean isStageActive(FlightConfiguration fc) {
return fc.isStageActive(getStageNumber());
}
@Override
public void copyFlightConfiguration(FlightConfigurationId oldConfigId, FlightConfigurationId newConfigId) {
@ -113,11 +130,11 @@ public class AxialStage extends ComponentAssembly implements FlightConfigurableC
/**
* returns if the object is a launch stage
* @param config the flight configuration which will check which stages are active
* @return if the object is a launch stage
*/
public boolean isLaunchStage(){
return ( this instanceof ParallelStage )
||( getRocket().getBottomCoreStage().equals(this));
public boolean isLaunchStage(FlightConfiguration config) {
return (getRocket().getBottomCoreStage(config).equals(this));
}
/**

View File

@ -60,8 +60,8 @@ public class FlightConfiguration implements FlightConfigurableParameter<FlightCo
}
/* Cached data */
final protected HashMap<Integer, StageFlags> stages = new HashMap<Integer, StageFlags>();
final protected HashMap<MotorConfigurationId, MotorConfiguration> motors = new HashMap<MotorConfigurationId, MotorConfiguration>();
final protected Map<Integer, StageFlags> stages = new HashMap<Integer, StageFlags>(); // Map of stage number to StageFlags of the corresponding stage
final protected Map<MotorConfigurationId, MotorConfiguration> motors = new HashMap<MotorConfigurationId, MotorConfiguration>();
final private Collection<MotorConfiguration> activeMotors = new ArrayList<MotorConfiguration>();
final private InstanceMap activeInstances = new InstanceMap();
@ -179,31 +179,52 @@ public class FlightConfiguration implements FlightConfigurableParameter<FlightCo
*/
public void setOnlyStage(final int stageNumber) {
_setAllStages(false);
_setStageActive(stageNumber, true);
_setStageActive(stageNumber, true, false);
updateMotors();
updateActiveInstances();
}
/**
/**
* This method flags the specified stage as requested. Other stages are unaffected.
*
*
* @param stageNumber stage number to flag
* @param _active inactive (<code>false</code>) or active (<code>true</code>)
* @param activateSubStages whether the sub-stages of the specified stage should be activated as well.
*/
private void _setStageActive(final int stageNumber, final boolean _active ) {
public void _setStageActive(final int stageNumber, final boolean _active, final boolean activateSubStages) {
if ((0 <= stageNumber) && (stages.containsKey(stageNumber))) {
stages.get(stageNumber).active = _active;
if (activateSubStages) {
// Set the active state of all the sub-stages as well.
for (AxialStage stage : rocket.getStage(stageNumber).getSubStages()) {
stages.get(stage.getStageNumber()).active = _active;
}
}
fireChangeEvent();
return;
}
log.error("error: attempt to retrieve via a bad stage number: " + stageNumber);
}
/**
* This method flags the specified stage as requested. Actives the sub-stages of the specified stage as well.
*
* @param stageNumber stage number to flag
* @param _active inactive (<code>false</code>) or active (<code>true</code>)
*/
public void _setStageActive(final int stageNumber, final boolean _active ) {
_setStageActive(stageNumber, _active, true);
}
public void toggleStage(final int stageNumber) {
if ((0 <= stageNumber) && (stages.containsKey(stageNumber))) {
StageFlags flags = stages.get(stageNumber);
flags.active = !flags.active;
// Set the active state of all the sub-stages as well.
for (AxialStage stage : rocket.getStage(stageNumber).getSubStages()) {
stages.get(stage.getStageNumber()).active = flags.active;
}
updateMotors();
updateActiveInstances();
@ -338,6 +359,18 @@ public class FlightConfiguration implements FlightConfigurableParameter<FlightCo
return results;
}
/**
* Return all the stages in this configuration.
* @return all the stages in this configuration.
*/
public List<AxialStage> getAllStages() {
List<AxialStage> stages = new ArrayList<>();
for (StageFlags flags : this.stages.values()) {
stages.add( rocket.getStage(flags.stageNumber));
}
return stages;
}
public List<AxialStage> getActiveStages() {
List<AxialStage> activeStages = new ArrayList<>();

View File

@ -26,7 +26,7 @@ import net.sf.openrocket.util.MathUtil;
*
* @author Sampo Niskanen <sampo.niskanen@iki.fi>
*/
public class InnerTube extends ThicknessRingComponent implements AxialPositionable, BoxBounded, Clusterable, RadialParent, MotorMount {
public class InnerTube extends ThicknessRingComponent implements AxialPositionable, BoxBounded, Clusterable, RadialParent, MotorMount, InsideColorComponent {
private static final Translator trans = Application.getTranslator();
private static final Logger log = LoggerFactory.getLogger(InnerTube.class);
@ -37,6 +37,8 @@ public class InnerTube extends ThicknessRingComponent implements AxialPositionab
private double overhang = 0;
private boolean isActingMount;
private MotorConfigurationSet motors;
private InsideColorComponentHandler insideColorComponentHandler = new InsideColorComponentHandler(this);
/**
* Main constructor.
@ -447,6 +449,16 @@ public class InnerTube extends ThicknessRingComponent implements AxialPositionab
return this.motors.toDebug();
}
@Override
public InsideColorComponentHandler getInsideColorComponentHandler() {
return this.insideColorComponentHandler;
}
@Override
public void setInsideColorComponentHandler(InsideColorComponentHandler handler) {
this.insideColorComponentHandler = handler;
}
@Override
public boolean addConfigListener(RocketComponent listener) {
boolean success = super.addConfigListener(listener);

View File

@ -111,8 +111,8 @@ public class ParallelStage extends AxialStage implements FlightConfigurableCompo
}
@Override
public boolean isLaunchStage(){
return true;
public boolean isLaunchStage(FlightConfiguration config) {
return config.isStageActive(this.stageNumber);
}
@Override

View File

@ -197,24 +197,37 @@ public class Rocket extends ComponentAssembly {
public AxialStage getStage( final int stageNumber ) {
return this.stageMap.get( stageNumber);
}
/*
* Returns the stage at the top of the central stack
*
* @Return a reference to the topmost stage
/**
* Get the topmost stage, only taking into account active stages from the flight configuration.
* @param config flight configuration dictating which stages are active
* @return the topmost active stage, or null if there are no active stages.
*/
public AxialStage getTopmostStage(){
return (AxialStage) getChild(0);
public AxialStage getTopmostStage(FlightConfiguration config) {
if (config == null) return null;
for (int i = 0; i < getChildCount(); i++) {
if (getChild(i) instanceof AxialStage && config.isStageActive(getChild(i).getStageNumber())) {
return (AxialStage) getChild(i);
}
}
return null;
}
/*
* Returns the stage at the top of the central stack
*
* @Return a reference to the topmost stage
/**
* Get the bottommost stage, only taking into account active stages from the flight configuration.
* @param config flight configuration dictating which stages are active
* @return the bottommost active stage, or null if there are no active stages.
*/
/*package-local*/ AxialStage getBottomCoreStage(){
// get last stage that's a direct child of the rocket.
return (AxialStage) children.get( children.size()-1 );
public AxialStage getBottomCoreStage(FlightConfiguration config) {
if (config == null) return null;
for (int i = getChildCount() - 1; i >= 0; i--) {
if (getChild(i) instanceof AxialStage && config.isStageActive(getChild(i).getStageNumber())) {
return (AxialStage) getChild(i);
}
}
return null;
}
@Override
@ -274,6 +287,11 @@ public class Rocket extends ComponentAssembly {
refType = type;
fireComponentChangeEvent(ComponentChangeEvent.NONFUNCTIONAL_CHANGE);
}
@Override
public double getLength() {
return selectedConfiguration.getLength();
}
public double getCustomReferenceLength() {
@ -291,6 +309,17 @@ public class Rocket extends ComponentAssembly {
fireComponentChangeEvent(ComponentChangeEvent.NONFUNCTIONAL_CHANGE);
}
}
@Override
public double getBoundingRadius() {
double bounding = 0;
for (RocketComponent comp : children) {
if (comp instanceof ComponentAssembly) {
bounding = Math.max(bounding, ((ComponentAssembly) comp).getBoundingRadius());
}
}
return bounding;
}
@ -390,10 +419,12 @@ public class Rocket extends ComponentAssembly {
this.stageMap = r.stageMap;
// these flight configurations need to reference the _this_ Rocket:
this.configSet.reset();
this.configSet.setDefault(new FlightConfiguration(this));
for (FlightConfigurationId key : r.configSet.map.keySet()) {
this.configSet.set(key, new FlightConfiguration(this, key));
}
this.selectedConfiguration = this.configSet.get(r.getSelectedConfiguration().getId());
this.perfectFinish = r.perfectFinish;
@ -735,6 +766,14 @@ public class Rocket extends ComponentAssembly {
fireComponentChangeEvent(ComponentChangeEvent.TREE_CHANGE);
return nextConfig.getFlightConfigurationID();
}
/**
* Return all the flight configurations of this rocket.
* @return all the flight configurations of this rocket.
*/
public FlightConfigurableParameterSet<FlightConfiguration> getFlightConfigurations() {
return this.configSet;
}
/**

View File

@ -1010,7 +1010,7 @@ public abstract class RocketComponent implements ChangeSource, Cloneable, Iterab
* If the length of a component is settable, the class must define the setter method
* itself.
*/
public final double getLength() {
public double getLength() {
mutex.verify();
return length;
}
@ -1545,6 +1545,11 @@ public abstract class RocketComponent implements ChangeSource, Cloneable, Iterab
AxialStage stage = (AxialStage) component;
this.getRocket().forgetStage(stage);
}
// Remove sub-stages of the removed component
for (AxialStage stage : component.getSubStages()) {
this.getRocket().forgetStage(stage);
}
this.checkComponentStructure();
component.checkComponentStructure();
@ -1749,6 +1754,21 @@ public abstract class RocketComponent implements ChangeSource, Cloneable, Iterab
}
throw new IllegalStateException("getStage() called on hierarchy without an AxialStage.");
}
/**
* Returns all the stages that are a child or sub-child of this component.
* @return all the stages that are a child or sub-child of this component.
*/
public final List<AxialStage> getSubStages() {
List<AxialStage> result = new LinkedList<>();
Iterator<RocketComponent> it = iterator(false);
while (it.hasNext()) {
RocketComponent c = it.next();
if (c instanceof AxialStage)
result.add((AxialStage) c);
}
return result;
}
/**
* Return the first component assembly component that this component belongs to.

View File

@ -45,7 +45,7 @@ public class BasicEventSimulationEngine implements SimulationEngine {
private final static double AOA_TUMBLE_CONDITION = Math.PI / 9.0;
// The thrust must be below this value for the transition to tumbling.
// TODO: this is an arbitrary value
// TODO HIGH: this is an arbitrary value
private final static double THRUST_TUMBLE_CONDITION = 0.01;
private SimulationStepper currentStepper;
@ -65,7 +65,9 @@ public class BasicEventSimulationEngine implements SimulationEngine {
// Set up rocket configuration
this.fcid = simulationConditions.getFlightConfigurationID();
FlightConfiguration simulationConfig = simulationConditions.getRocket().getFlightConfiguration( this.fcid).clone();
FlightConfiguration origConfig = simulationConditions.getRocket().getFlightConfiguration(this.fcid);
FlightConfiguration simulationConfig = origConfig.clone();
simulationConfig.copyStages(origConfig); // Clone the stage activation configuration
if ( ! simulationConfig.hasMotors() ) {
throw new MotorIgnitionException(trans.get("BasicEventSimulationEngine.error.noMotorsDefined"));
}
@ -74,7 +76,7 @@ public class BasicEventSimulationEngine implements SimulationEngine {
currentStatus.getEventQueue().add(new FlightEvent(FlightEvent.Type.LAUNCH, 0, simulationConditions.getRocket()));
{
// main simulation branch
final String branchName = simulationConfig.getRocket().getTopmostStage().getName();
final String branchName = simulationConfig.getRocket().getTopmostStage(currentStatus.getConfiguration()).getName();
currentStatus.setFlightData(new FlightDataBranch( branchName, FlightDataType.TYPE_TIME));
}
toSimulate.push(currentStatus);
@ -273,9 +275,7 @@ public class BasicEventSimulationEngine implements SimulationEngine {
// Check for motor ignition events, add ignition events to queue
for (MotorClusterState state : currentStatus.getActiveMotors() ){
if( state.testForIgnition(event )){
final double simulationTime = currentStatus.getSimulationTime() ;
if (state.testForIgnition(currentStatus.getConfiguration(), event)) {
MotorClusterState sourceState = (MotorClusterState) event.getData();
double ignitionDelay = 0;
if (event.getType() == FlightEvent.Type.BURNOUT)
@ -543,7 +543,7 @@ public class BasicEventSimulationEngine implements SimulationEngine {
}
// TODO : FUTURE : do not hard code the 1200 (maybe even make it configurable by the user)
// TODO FUTURE : do not hard code the 1200 (maybe even make it configurable by the user)
if( 1200 < currentStatus.getSimulationTime() ){
ret = false;
log.error("Simulation hit max time (1200s): aborting.");
@ -553,6 +553,7 @@ public class BasicEventSimulationEngine implements SimulationEngine {
// If no motor has ignited, abort
if (!currentStatus.isMotorIgnited()) {
// TODO MEDIUM: display this as a warning to the user (e.g. highlight the cell in the simulation panel in red and a hover: 'make sure the motor ignition is correct' or something)
throw new MotorIgnitionException(trans.get("BasicEventSimulationEngine.error.noIgnition"));
}

View File

@ -172,7 +172,7 @@ public class FlightEvent implements Comparable<FlightEvent> {
* @return
*/
public void validate(){
if( this.time == Double.NaN ){
if(Double.isNaN(this.time)){
throw new IllegalStateException(type.name()+" event has a NaN time!");
}
switch( this.type ){

View File

@ -4,6 +4,7 @@ import net.sf.openrocket.motor.IgnitionEvent;
import net.sf.openrocket.motor.Motor;
import net.sf.openrocket.motor.MotorConfiguration;
import net.sf.openrocket.motor.MotorConfigurationId;
import net.sf.openrocket.rocketcomponent.FlightConfiguration;
import net.sf.openrocket.rocketcomponent.MotorMount;
import net.sf.openrocket.rocketcomponent.RocketComponent;
@ -121,8 +122,8 @@ public class MotorClusterState {
/**
* Compute the average thrust over an interval.
*
* @param simulationTime
* @param cond
* @param startSimulationTime start time of the averaging interval
* @param endSimulationTime end time of the averaging interval
* @return
*/
public double getAverageThrust( final double startSimulationTime, final double endSimulationTime) {
@ -141,7 +142,6 @@ public class MotorClusterState {
* Compute the average thrust over an interval.
*
* @param simulationTime
* @param cond
* @return
*/
public double getThrust( final double simulationTime){
@ -182,9 +182,9 @@ public class MotorClusterState {
currentState = ThrustState.ARMED;
}
public boolean testForIgnition( final FlightEvent _event ){
public boolean testForIgnition(FlightConfiguration flightConfiguration, final FlightEvent _event ){
RocketComponent mount = (RocketComponent) this.getMount();
return getIgnitionEvent().isActivationEvent( _event, mount);
return getIgnitionEvent().isActivationEvent(flightConfiguration, _event, mount);
}
public String toDescription(){

View File

@ -68,6 +68,7 @@ public abstract class Preferences implements ChangeSource {
public static final String PREFERRED_THRUST_CURVE_MOTOR_NODE = "preferredThrustCurveMotors";
private static final String AUTO_OPEN_LAST_DESIGN = "AUTO_OPEN_LAST_DESIGN";
private static final String OPEN_LEFTMOST_DESIGN_TAB = "OPEN_LEFTMOST_DESIGN_TAB";
private static final String SHOW_MARKERS = "SHOW_MARKERS";
private static final String SHOW_ROCKSIM_FORMAT_WARNING = "SHOW_ROCKSIM_FORMAT_WARNING";
//Preferences related to 3D graphics
@ -469,7 +470,26 @@ public abstract class Preferences implements ChangeSource {
public final boolean isAlwaysOpenLeftmostTab() {
return this.getBoolean(OPEN_LEFTMOST_DESIGN_TAB, false);
}
/**
* Set whether pod set/booster markers should only be displayed when the pod set/booster is selected.
* @param enabled true if pod set/booster markers should only be displayed when the pod set/booster is selected,
* false if they should be displayed permanently.
*/
public final void setShowMarkers(boolean enabled) {
this.putBoolean(SHOW_MARKERS, enabled);
}
/**
* Answer if pod set/booster markers should only be displayed when the pod set/booster is selected
*
* @return true if pod set/booster markers should only be displayed when the pod set/booster is selected,
* false if they should be displayed permanently.
*/
public final boolean isShowMarkers() {
return this.getBoolean(SHOW_MARKERS, false);
}
/**
* Return the OpenRocket unique ID.
*

View File

@ -267,22 +267,25 @@ public class BarrowmanCalculatorTest {
public void testContinuousRocket() {
Rocket rocket = TestRockets.makeEstesAlphaIII();
AerodynamicCalculator calc = new BarrowmanCalculator();
FlightConfiguration configuration = rocket.getSelectedConfiguration();
assertTrue("Estes Alpha III should be continous: ", calc.isContinuous( rocket));
assertTrue("Estes Alpha III should be continous: ", calc.isContinuous(configuration, rocket));
}
@Test
public void testContinuousRocketWithStrapOns() {
Rocket rocket = TestRockets.makeFalcon9Heavy();
AerodynamicCalculator calc = new BarrowmanCalculator();
FlightConfiguration configuration = rocket.getSelectedConfiguration();
assertTrue("F9H should be continuous: ", calc.isContinuous( rocket));
assertTrue("F9H should be continuous: ", calc.isContinuous(configuration, rocket));
}
@Test
public void testRadialDiscontinuousRocket() {
Rocket rocket = TestRockets.makeEstesAlphaIII();
AerodynamicCalculator calc = new BarrowmanCalculator();
FlightConfiguration configuration = rocket.getSelectedConfiguration();
NoseCone nose = (NoseCone)rocket.getChild(0).getChild(0);
BodyTube body = (BodyTube)rocket.getChild(0).getChild(1);
@ -291,13 +294,14 @@ public class BarrowmanCalculatorTest {
body.setOuterRadius( 0.012 );
body.setName( body.getName()+" << discontinuous");
assertFalse(" Estes Alpha III has an undetected discontinuity:", calc.isContinuous( rocket));
assertFalse(" Estes Alpha III has an undetected discontinuity:", calc.isContinuous(configuration, rocket));
}
@Test
public void testRadialDiscontinuityWithStrapOns() {
Rocket rocket = TestRockets.makeFalcon9Heavy();
AerodynamicCalculator calc = new BarrowmanCalculator();
FlightConfiguration configuration = rocket.getSelectedConfiguration();
final AxialStage coreStage = (AxialStage)rocket.getChild(1);
final ParallelStage booster = (ParallelStage)coreStage.getChild(0).getChild(0);
@ -309,7 +313,7 @@ public class BarrowmanCalculatorTest {
body.setOuterRadius( 0.012 );
body.setName( body.getName()+" << discontinuous");
assertFalse(" Missed discontinuity in Falcon 9 Heavy:", calc.isContinuous( rocket));
assertFalse(" Missed discontinuity in Falcon 9 Heavy:", calc.isContinuous(configuration, rocket));
}
@Test

View File

@ -294,9 +294,22 @@ public class FlightConfigurationTest extends BaseTestCase {
config.toggleStage(0);
assertThat(" toggle stage #0: ", config.isStageActive(0), equalTo(false));
AxialStage sustainer = rkt.getTopmostStage();
AxialStage booster = rkt.getBottomCoreStage();
AxialStage sustainer = rkt.getTopmostStage(config);
AxialStage booster = rkt.getBottomCoreStage(config);
assertThat(" sustainer stage is stage #1: ", sustainer.getStageNumber(), equalTo(1));
assertThat(" booster stage is stage #1: ", booster.getStageNumber(), equalTo(1));
config.setAllStages();
config._setStageActive(1, false);
sustainer = rkt.getTopmostStage(config);
booster = rkt.getBottomCoreStage(config);
assertThat(" sustainer stage is stage #1: ", sustainer.getStageNumber(), equalTo(0));
assertThat(" booster stage is stage #1: ", booster.getStageNumber(), equalTo(0));
config.setAllStages();
sustainer = rkt.getTopmostStage(config);
booster = rkt.getBottomCoreStage(config);
assertThat(" sustainer stage is stage #0: ", sustainer.getStageNumber(), equalTo(0));
assertThat(" booster stage is stage #1: ", booster.getStageNumber(), equalTo(1));
@ -351,7 +364,6 @@ public class FlightConfigurationTest extends BaseTestCase {
selected.clearAllStages();
selected.toggleStage(1);
selected.toggleStage(2);
// vvvv Test Target vvvv
InstanceMap instances = selected.getActiveInstances();

View File

@ -0,0 +1,305 @@
package net.sf.openrocket.simulation;
import net.sf.openrocket.document.Simulation;
import net.sf.openrocket.rocketcomponent.FlightConfiguration;
import net.sf.openrocket.rocketcomponent.FlightConfigurationId;
import net.sf.openrocket.rocketcomponent.Rocket;
import net.sf.openrocket.simulation.exception.MotorIgnitionException;
import net.sf.openrocket.simulation.exception.SimulationException;
import net.sf.openrocket.simulation.listeners.AbstractSimulationListener;
import net.sf.openrocket.simulation.listeners.SimulationListener;
import net.sf.openrocket.util.BaseTestCase.BaseTestCase;
import net.sf.openrocket.util.TestRockets;
import org.junit.Assert;
import org.junit.Test;
/**
* Test class that tests the effect on the simulation results of activating/deactivating stages.
*
* @author Sibo Van Gool <sibo.vangool@hotmail.com>
*/
public class DisableStageTest extends BaseTestCase {
/**
* Tests that the simulation results are correct when a single stage is deactivated and re-activated.
*/
@Test
public void testSingleStage() throws SimulationException {
//// Test disabling the stage
Rocket rocket = TestRockets.makeEstesAlphaIII();
Simulation simDisabled = new Simulation(rocket);
simDisabled.setFlightConfigurationId(TestRockets.TEST_FCID_0);
simDisabled.getActiveConfiguration()._setStageActive(0, false);
simDisabled.getOptions().setISAAtmosphere(true);
simDisabled.getOptions().setTimeStep(0.05);
SimulationListener simulationListener = new AbstractSimulationListener();
// Since there are no stages, the simulation should throw an exception.
try {
simDisabled.simulate(simulationListener);
} catch (SimulationException e) {
if (!(e instanceof MotorIgnitionException)) {
Assert.fail("Simulation should have thrown a MotorIgnitionException");
}
}
//// Test re-enableing the stage.
Rocket rocketOriginal = TestRockets.makeEstesAlphaIII();
Simulation simOriginal = new Simulation(rocketOriginal);
simOriginal.setFlightConfigurationId(TestRockets.TEST_FCID_0);
simOriginal.getOptions().setISAAtmosphere(true);
simOriginal.getOptions().setTimeStep(0.05);
simDisabled.getActiveConfiguration().setAllStages(); // Re-enable all stages.
double delta = 0.05; // 5 % error margin (simulations are not exact)
compareSims(simOriginal, simDisabled, simulationListener, delta);
}
/**
* Tests that the simulation results are correct when the last stage of a multi-stage rocket is deactivated and re-activated.
*/
@Test
public void testMultiStageLastDisabled() {
//// Test disabling the stage
Rocket rocketRemoved = TestRockets.makeBeta(); // Rocket with the last stage removed
Rocket rocketDisabled = TestRockets.makeBeta(); // Rocket with the last stage disabled
int stageNr = rocketRemoved.getChildCount() - 1;
rocketRemoved.removeChild(stageNr);
FlightConfiguration fc = rocketDisabled.getFlightConfiguration(TestRockets.TEST_FCID_1);
fc._setStageActive(stageNr, false);
Simulation simRemoved = new Simulation(rocketRemoved);
simRemoved.setFlightConfigurationId(TestRockets.TEST_FCID_1);
simRemoved.getOptions().setISAAtmosphere(true);
simRemoved.getOptions().setTimeStep(0.05);
Simulation simDisabled = new Simulation(rocketDisabled);
simDisabled.setFlightConfigurationId(TestRockets.TEST_FCID_1);
simDisabled.getOptions().setISAAtmosphere(true);
simDisabled.getOptions().setTimeStep(0.05);
SimulationListener simulationListener = new AbstractSimulationListener();
double delta = 0.05; // 5 % error margin (simulations are not exact)
compareSims(simRemoved, simDisabled, simulationListener, delta);
//// Test re-enableing the stage.
Rocket rocketOriginal = TestRockets.makeBeta();
Simulation simOriginal = new Simulation(rocketOriginal);
simOriginal.setFlightConfigurationId(TestRockets.TEST_FCID_1);
simOriginal.getOptions().setISAAtmosphere(true);
simOriginal.getOptions().setTimeStep(0.05);
simDisabled.getActiveConfiguration().setAllStages();
compareSims(simOriginal, simDisabled, simulationListener, delta);
}
/**
* Tests that the simulation results are correct when the first stage of a multi-stage rocket is deactivated and re-activated.
*/
// Don't even know if this test was useful, but simulation results vary wildly because the first stage is disabled,
// so I'm just gonna ignore this test.
/*@Test
public void testMultiStageFirstDisabled() {
//// Test disabling the stage
Rocket rocketRemoved = TestRockets.makeBeta(); // Rocket with the last stage removed
Rocket rocketDisabled = TestRockets.makeBeta(); // Rocket with the last stage disabled
// You need to disable the second stage body tube going into automatic radius mode, otherwise the
// removed and disabled rocket will have different results (removed rocket will have a different diameter)
BodyTube bodyTube = (BodyTube) rocketRemoved.getChild(1).getChild(0);
bodyTube.setOuterRadiusAutomatic(false);
int stageNr = 0;
rocketRemoved.removeChild(stageNr);
FlightConfiguration fc = rocketDisabled.getFlightConfiguration(TestRockets.TEST_FCID_1);
fc._setStageActive(stageNr, false);
Simulation simRemoved = new Simulation(rocketRemoved);
simRemoved.setFlightConfigurationId(TestRockets.TEST_FCID_1);
simRemoved.getOptions().setISAAtmosphere(true);
simRemoved.getOptions().setTimeStep(0.05);
Simulation simDisabled = new Simulation(rocketDisabled);
simDisabled.setFlightConfigurationId(TestRockets.TEST_FCID_1);
simDisabled.getOptions().setISAAtmosphere(true);
simDisabled.getOptions().setTimeStep(0.05);
SimulationListener simulationListener = new AbstractSimulationListener();
double delta = 0.1; // 10 % error margin (simulations are very unstable and not exact when the first stage is disabled...)
compareSims(simRemoved, simDisabled, simulationListener, delta);
//// Test re-enableing the stage.
Rocket rocketOriginal = TestRockets.makeBeta();
Simulation simOriginal = new Simulation(rocketOriginal);
simOriginal.setFlightConfigurationId(TestRockets.TEST_FCID_1);
simOriginal.getOptions().setISAAtmosphere(true);
simOriginal.getOptions().setTimeStep(0.05);
simDisabled.getActiveConfiguration().setAllStages();
compareSims(simOriginal, simDisabled, simulationListener, delta);
}*/
/**
* Tests that the simulation results are correct when a booster stage is deactivated and re-activated.
*/
@Test
public void testBooster1() {
//// Test disabling the stage
Rocket rocketRemoved = TestRockets.makeFalcon9Heavy(); // Rocket with the last stage removed
Rocket rocketDisabled = TestRockets.makeFalcon9Heavy(); // Rocket with the last stage disabled
FlightConfigurationId fcid = new FlightConfigurationId(TestRockets.FALCON_9H_FCID_1);
int stageNr = 2; // Stage 2 is the Parallel Booster Stage
rocketRemoved.getChild(1).getChild(0).removeChild(0); // Remove the Parallel Booster Stage
FlightConfiguration fc = rocketDisabled.getFlightConfiguration(fcid);
fc._setStageActive(stageNr, false);
Simulation simRemoved = new Simulation(rocketRemoved);
simRemoved.setFlightConfigurationId(fcid);
simRemoved.getOptions().setISAAtmosphere(true);
simRemoved.getOptions().setTimeStep(0.05);
Simulation simDisabled = new Simulation(rocketDisabled);
simDisabled.setFlightConfigurationId(fcid);
simDisabled.getOptions().setISAAtmosphere(true);
simDisabled.getOptions().setTimeStep(0.05);
SimulationListener simulationListener = new AbstractSimulationListener();
double delta = 0.05; // 5 % error margin (simulations are not exact)
compareSims(simRemoved, simDisabled, simulationListener, delta);
//// Test re-enableing the stage.
Rocket rocketOriginal = TestRockets.makeFalcon9Heavy();
Simulation simOriginal = new Simulation(rocketOriginal);
simOriginal.setFlightConfigurationId(fcid);
simOriginal.getOptions().setISAAtmosphere(true);
simOriginal.getOptions().setTimeStep(0.05);
simDisabled.getActiveConfiguration().setAllStages();
compareSims(simOriginal, simDisabled, simulationListener, delta);
}
/**
* Tests that the simulation results are correct when the parent stage of a booster stage is deactivated and re-activated.
*/
@Test
public void testBooster2() {
//// Test disabling the stage
Rocket rocketRemoved = TestRockets.makeFalcon9Heavy(); // Rocket with the last stage removed
Rocket rocketDisabled = TestRockets.makeFalcon9Heavy(); // Rocket with the last stage disabled
FlightConfigurationId fid = new FlightConfigurationId(TestRockets.FALCON_9H_FCID_1);
int stageNr = 1; // Stage 1 is the Parallel Booster Stage's parent stage
rocketRemoved.getChild(1).removeChild(0); // Remove the Parallel Booster Stage's parent stage
FlightConfiguration fc = rocketDisabled.getFlightConfiguration(fid);
fc._setStageActive(stageNr, false);
Simulation simRemoved = new Simulation(rocketRemoved);
simRemoved.setFlightConfigurationId(fid);
simRemoved.getOptions().setISAAtmosphere(true);
simRemoved.getOptions().setTimeStep(0.05);
Simulation simDisabled = new Simulation(rocketDisabled);
simDisabled.setFlightConfigurationId(fid);
simDisabled.getOptions().setISAAtmosphere(true);
simDisabled.getOptions().setTimeStep(0.05);
SimulationListener simulationListener = new AbstractSimulationListener();
// There should be no motors left at this point, so a no motors exception should be thrown
try {
simRemoved.simulate(simulationListener);
} catch (SimulationException e) {
if (!(e instanceof MotorIgnitionException)) {
Assert.fail("Simulation failed: " + e);
}
}
try {
simDisabled.simulate(simulationListener);
} catch (SimulationException e) {
if (!(e instanceof MotorIgnitionException)) {
Assert.fail("Simulation failed: " + e);
}
}
//// Test re-enableing the stage.
Rocket rocketOriginal = TestRockets.makeFalcon9Heavy();
Simulation simOriginal = new Simulation(rocketOriginal);
simOriginal.setFlightConfigurationId(fid);
simOriginal.getOptions().setISAAtmosphere(true);
simOriginal.getOptions().setTimeStep(0.05);
simDisabled.getActiveConfiguration().setAllStages();
double delta = 0.05; // 5 % error margin (simulations are not exact)
compareSims(simOriginal, simDisabled, simulationListener, delta);
}
/**
* Compare simActual to simExpected and fail the unit test if there was an error during simulation or
* the two don't match.
* Tested parameters:
* - maxAcceleration
* - maxAltitude
* - maxVelocity
* - maxMachNumber
* - flightTime
* - launchRodVelocity
* - deploymentVelocity
* - groundHitVelocity
* @param simExpected the expected simulation results
* @param simActual the actual simulation results
* @param simulationListener the simulation listener to use for the comparison
* @param delta the error margin for the comparison (e.g. 0.05 = 5 % error margin)
*/
private void compareSims(Simulation simExpected, Simulation simActual,
SimulationListener simulationListener, double delta) {
try {
simExpected.simulate(simulationListener);
double maxAccelerationOriginal = simExpected.getSimulatedData().getMaxAcceleration();
double maxAltitudeOriginal = simExpected.getSimulatedData().getMaxAltitude();
double maxVelocityOriginal = simExpected.getSimulatedData().getMaxVelocity();
double maxMachNumberOriginal = simExpected.getSimulatedData().getMaxMachNumber();
double flightTimeOriginal = simExpected.getSimulatedData().getFlightTime();
double timeToApogeeOriginal = simExpected.getSimulatedData().getTimeToApogee();
double launchRodVelocityOriginal = simExpected.getSimulatedData().getLaunchRodVelocity();
double deploymentVelocityOriginal = simExpected.getSimulatedData().getDeploymentVelocity();
double groundHitVelocityOriginal = simExpected.getSimulatedData().getGroundHitVelocity();
simActual.simulate(simulationListener);
double maxAccelerationDisabled = simActual.getSimulatedData().getMaxAcceleration();
double maxAltitudeDisabled = simActual.getSimulatedData().getMaxAltitude();
double maxVelocityDisabled = simActual.getSimulatedData().getMaxVelocity();
double maxMachNumberDisabled = simActual.getSimulatedData().getMaxMachNumber();
double flightTimeDisabled = simActual.getSimulatedData().getFlightTime();
double timeToApogeeDisabled = simActual.getSimulatedData().getTimeToApogee();
double launchRodVelocityDisabled = simActual.getSimulatedData().getLaunchRodVelocity();
double deploymentVelocityDisabled = simActual.getSimulatedData().getDeploymentVelocity();
double groundHitVelocityDisabled = simActual.getSimulatedData().getGroundHitVelocity();
Assert.assertEquals(maxAccelerationOriginal, maxAccelerationDisabled, maxAccelerationOriginal * delta);
Assert.assertEquals(maxAltitudeOriginal, maxAltitudeDisabled, maxAltitudeOriginal * delta);
Assert.assertEquals(maxVelocityOriginal, maxVelocityDisabled, maxVelocityOriginal * delta);
Assert.assertEquals(maxMachNumberOriginal, maxMachNumberDisabled, maxMachNumberOriginal * delta);
Assert.assertEquals(flightTimeOriginal, flightTimeDisabled, flightTimeOriginal * delta);
Assert.assertEquals(timeToApogeeOriginal, timeToApogeeDisabled, timeToApogeeOriginal * delta);
Assert.assertEquals(launchRodVelocityOriginal, launchRodVelocityDisabled, launchRodVelocityOriginal * delta);
Assert.assertEquals(deploymentVelocityOriginal, deploymentVelocityDisabled, deploymentVelocityOriginal * delta);
Assert.assertEquals(groundHitVelocityOriginal, groundHitVelocityDisabled, groundHitVelocityOriginal * delta);
} catch (SimulationException e) {
Assert.fail("Simulation failed: " + e);
}
}
}

View File

@ -17,6 +17,8 @@
<classpathentry kind="lib" path="/OpenRocket Core/lib/aopalliance.jar"/>
<classpathentry kind="lib" path="/OpenRocket Core/lib/commonmark-0.19.0.jar"/>
<classpathentry kind="lib" path="/OpenRocket Core/lib/javax.inject.jar"/>
<classpathentry kind="lib" path="/OpenRocket Core/lib/javax.json-1.1.3.jar"/>
<classpathentry kind="lib" path="/OpenRocket Core/lib/javax.json-api-1.1.3.jar"/>
<classpathentry kind="lib" path="/OpenRocket Core/resources"/>
<classpathentry kind="lib" path="resources"/>
<classpathentry kind="lib" path="lib/miglayout-4.0-swing.jar" sourcepath="reference/miglayout-4.0-sources.jar"/>

View File

@ -154,7 +154,7 @@
depends="build">
<for param="vendor-dir">
<dirset dir="${resources-src.dir}/datafiles/rocksim_components"
<dirset dir="${resources-src.dir}/datafiles/rocksim_src"
includes="*"/>
<sequential>
<propertyregex property="vendor"

View File

@ -1,8 +1,14 @@
package net.sf.openrocket.gui;
import javax.swing.JSpinner;
import javax.swing.JTextField;
import javax.swing.SwingUtilities;
import javax.swing.text.DefaultFormatter;
import javax.swing.text.DefaultFormatterFactory;
import java.awt.event.FocusEvent;
import java.awt.event.FocusListener;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
/**
* Editable editor for a JSpinner. Simply uses JSpinner.DefaultEditor, which has been made
@ -22,6 +28,59 @@ public class SpinnerEditor extends JSpinner.DefaultEditor {
DefaultFormatterFactory dff = (DefaultFormatterFactory) getTextField().getFormatterFactory();
DefaultFormatter formatter = (DefaultFormatter) dff.getDefaultFormatter();
formatter.setOverwriteMode(false);
// Add listeners to select all the text when the field is focussed
{
getTextField().addFocusListener(new FocusListener() {
@Override
public void focusGained(FocusEvent e) {
selectAllText();
}
@Override
public void focusLost(FocusEvent e) {
}
});
getTextField().addMouseListener(new MouseListener() {
private boolean isFocussed = false; // Checks whether the text field was focussed when it was clicked upon
@Override
public void mouseClicked(MouseEvent e) {
// If the text field was focussed when it was clicked upon instead of e.g. tab-switching to gain focus,
// then the select all action from the focus listener is ignored (it is replaced by a cursor-click event).
// So if we detect such a focus change, then redo the select all action.
if (!isFocussed) {
SwingUtilities.invokeLater(new Runnable() {
@Override
public void run() {
JTextField tf = (JTextField) e.getSource();
tf.selectAll();
}
});
}
}
@Override
public void mousePressed(MouseEvent e) {
JTextField tf = (JTextField) e.getSource();
isFocussed = tf.hasFocus();
}
@Override
public void mouseReleased(MouseEvent e) {
}
@Override
public void mouseEntered(MouseEvent e) {
}
@Override
public void mouseExited(MouseEvent e) {
}
});
}
}
/**
@ -33,5 +92,17 @@ public class SpinnerEditor extends JSpinner.DefaultEditor {
this(spinner);
getTextField().setColumns(cols);
}
/**
* Highlights all the text in the text field.
*/
private void selectAllText() {
SwingUtilities.invokeLater(new Runnable() {
@Override
public void run() {
getTextField().selectAll();
}
});
}
}

View File

@ -5,16 +5,14 @@ import java.util.List;
import javax.swing.AbstractListModel;
import javax.swing.ComboBoxModel;
import javax.swing.SwingUtilities;
import net.sf.openrocket.database.ComponentPresetDatabase;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import net.sf.openrocket.gui.configdialog.RocketComponentConfig;
import net.sf.openrocket.database.Database;
import net.sf.openrocket.database.DatabaseListener;
import net.sf.openrocket.document.OpenRocketDocument;
import net.sf.openrocket.gui.dialogs.preset.ComponentPresetChooserDialog;
import net.sf.openrocket.l10n.Translator;
import net.sf.openrocket.logging.Markers;
import net.sf.openrocket.preset.ComponentPreset;
@ -29,8 +27,7 @@ public class PresetModel extends AbstractListModel implements ComboBoxModel, Com
private static final Logger log = LoggerFactory.getLogger(PresetModel.class);
private static final Translator trans = Application.getTranslator();
private static final String NONE_SELECTED = trans.get("lbl.select");
private static final String SELECT_DATABASE = trans.get("lbl.database");
private static final String NONE_SELECTED = String.format("<html><i>%s</i></html>", trans.get("PresetModel.lbl.custompreset"));
private final Component parent;
private final RocketComponent component;
@ -50,7 +47,7 @@ public class PresetModel extends AbstractListModel implements ComboBoxModel, Com
@Override
public int getSize() {
return presets.size() + 2;
return presets.size() + 1;
}
@Override
@ -58,9 +55,6 @@ public class PresetModel extends AbstractListModel implements ComboBoxModel, Com
if (index == 0) {
return NONE_SELECTED;
}
if (index == getSize() - 1) {
return SELECT_DATABASE;
}
return presets.get(index - 1);
}
@ -72,24 +66,10 @@ public class PresetModel extends AbstractListModel implements ComboBoxModel, Com
throw new BugException("item is null");
} else if (item.equals(NONE_SELECTED)) {
component.clearPreset();
} else if (item.equals(SELECT_DATABASE)) {
SwingUtilities.invokeLater(new Runnable() {
@Override
public void run() {
((ComponentPresetDatabase) Application.getComponentPresetDao()).addDatabaseListener(PresetModel.this);
ComponentPresetChooserDialog dialog =
new ComponentPresetChooserDialog(SwingUtilities.getWindowAncestor(parent), component);
dialog.setVisible(true);
ComponentPreset preset = dialog.getSelectedComponentPreset();
if (preset != null) {
setSelectedItem(preset);
}
((ComponentPresetDatabase) Application.getComponentPresetDao()).removeChangeListener(PresetModel.this);
}
});
} else {
document.addUndoPosition("Use Preset " + component.getComponentName());
component.loadPreset((ComponentPreset) item);
((RocketComponentConfig) parent).setFocusElement();
}
}

View File

@ -24,21 +24,49 @@ public class ConfigurationComboBox extends JComboBox<FlightConfiguration> implem
public class ConfigurationModel implements MutableComboBoxModel<FlightConfiguration> {
private final Rocket rkt;
public ConfigurationModel(final Rocket _rkt) {
private FlightConfiguration selectedConfig;
private final boolean updateRocketConfig;
private final ConfigurationModel listener;
/**
* @param _rkt the rocket to get the configurations from and to (optionally) change the rocket's selected configuration
* @param _updateRocketConfig whether to update the rocket's selected configuration based on the selected combo box item,
* or just change the combo box item without altering the rocket's configuration.
* @param listener model that should change its selected item to this model's selected item
*/
public ConfigurationModel(final Rocket _rkt, boolean _updateRocketConfig, ConfigurationModel listener) {
this.rkt = _rkt;
this.updateRocketConfig = _updateRocketConfig;
this.selectedConfig = this.rkt.getSelectedConfiguration();
this.listener = listener;
}
public ConfigurationModel(final Rocket _rkt, boolean _updateRocketConfig) {
this(_rkt, _updateRocketConfig, null);
}
@Override
public FlightConfiguration getSelectedItem() {
return rkt.getSelectedConfiguration();
if (updateRocketConfig) {
return rkt.getSelectedConfiguration();
} else {
return selectedConfig;
}
}
@Override
public void setSelectedItem(Object nextItem) {
if( nextItem instanceof FlightConfiguration ){
FlightConfigurationId selectedId = ((FlightConfiguration)nextItem).getId();
rkt.setSelectedConfiguration(selectedId);
if (updateRocketConfig) {
rkt.setSelectedConfiguration(selectedId);
} else {
selectedConfig = rkt.getFlightConfiguration(selectedId);
}
if (listener != null) {
listener.setSelectedItem(nextItem);
}
}
}
@ -79,9 +107,15 @@ public class ConfigurationComboBox extends JComboBox<FlightConfiguration> implem
private final Rocket rkt;
public ConfigurationComboBox(Rocket _rkt) {
/**
* @param _rkt the rocket to get the configurations from and to (optionally) change the rocket's selected configuration
* @param _updateRocketConfig whether to update the rocket's selected configuration based on the selected combo box item,
* or just change the combo box item without altering the rocket's configuration.
*/
public ConfigurationComboBox(Rocket _rkt, boolean _updateRocketConfig) {
rkt = _rkt;
setModel(new ConfigurationModel(rkt));
final ConfigurationModel model = new ConfigurationModel(rkt, _updateRocketConfig);
setModel(model);
rkt.addChangeListener(this);
addPopupMenuListener(new PopupMenuListener() {
@ -89,12 +123,18 @@ public class ConfigurationComboBox extends JComboBox<FlightConfiguration> implem
public void popupMenuWillBecomeInvisible(PopupMenuEvent e) {}
public void popupMenuWillBecomeVisible(PopupMenuEvent e) {
setModel(new ConfigurationModel(rkt));
final ConfigurationModel model2 = new ConfigurationModel(rkt, _updateRocketConfig, model);
model2.setSelectedItem(model.getSelectedItem());
setModel(model2);
}
});
}
public ConfigurationComboBox(Rocket _rkt) {
this(_rkt, true);
}
@Override
public void stateChanged(EventObject e) {

View File

@ -6,6 +6,8 @@ import javax.swing.JDialog;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JSpinner;
import javax.swing.JTextField;
import javax.swing.SwingUtilities;
import net.miginfocom.swing.MigLayout;
import net.sf.openrocket.document.OpenRocketDocument;
@ -23,6 +25,12 @@ import net.sf.openrocket.rocketcomponent.SymmetricComponent;
import net.sf.openrocket.startup.Application;
import net.sf.openrocket.unit.UnitGroup;
import java.awt.event.FocusEvent;
import java.awt.event.FocusListener;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.util.Arrays;
@SuppressWarnings("serial")
public class BodyTubeConfig extends RocketComponentConfig {
@ -43,6 +51,7 @@ public class BodyTubeConfig extends RocketComponentConfig {
JSpinner spin = new JSpinner(length.getSpinnerModel());
spin.setEditor(new SpinnerEditor(spin));
focusElement = spin;
panel.add(spin, "growx");
panel.add(new UnitSelector(length), "growx");

View File

@ -1,18 +1,24 @@
package net.sf.openrocket.gui.configdialog;
import java.awt.GraphicsDevice;
import java.awt.GraphicsEnvironment;
import java.awt.Rectangle;
import java.awt.Window;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import java.util.Arrays;
import java.util.List;
import javax.swing.JDialog;
import net.sf.openrocket.document.OpenRocketDocument;
import net.sf.openrocket.gui.main.BasicFrame;
import net.sf.openrocket.gui.util.GUIUtil;
import net.sf.openrocket.gui.util.SwingPreferences;
import net.sf.openrocket.gui.util.WindowLocationUtil;
import net.sf.openrocket.l10n.Translator;
import net.sf.openrocket.rocketcomponent.AxialStage;
import net.sf.openrocket.rocketcomponent.ComponentChangeEvent;
@ -230,8 +236,9 @@ public class ComponentConfigDialog extends JDialog implements ComponentChangeLis
* @param document the document to configure.
* @param component the component to configure.
* @param rememberPreviousTab if true, the previous tab will be remembered and used for the new dialog
* @param includeUndoModify if true, include a 'Modify component' undo action
*/
public static void showDialog(Window parent, OpenRocketDocument document, RocketComponent component, boolean rememberPreviousTab) {
public static void showDialog(Window parent, OpenRocketDocument document, RocketComponent component, boolean rememberPreviousTab, boolean includeUndoModify) {
if (dialog != null) {
// Don't remember the previous tab for rockets or stages, because this will leave you in the override tab for
// the next component, which is generally not what you want.
@ -256,15 +263,32 @@ public class ComponentConfigDialog extends JDialog implements ComponentChangeLis
dialog = new ComponentConfigDialog(parent, document, component);
dialog.setVisible(true);
if (parent instanceof BasicFrame && BasicFrame.getStartupFrame() == parent) {
WindowLocationUtil.moveIfOutsideOfParentMonitor(dialog, parent);
}
////Modify
if (component.getConfigListeners().size() == 0) {
document.addUndoPosition(trans.get("ComponentCfgDlg.Modify") + " " + component.getComponentName());
} else {
document.addUndoPosition(trans.get("ComponentCfgDlg.ModifyComponents"));
if (includeUndoModify) {
if (component.getConfigListeners().size() == 0) {
document.addUndoPosition(trans.get("ComponentCfgDlg.Modify") + " " + component.getComponentName());
} else {
document.addUndoPosition(trans.get("ComponentCfgDlg.ModifyComponents"));
}
}
}
/**
* A singleton configuration dialog. Will create and show a new dialog if one has not
* previously been used, or update the dialog and show it if a previous one exists.
*
* @param document the document to configure.
* @param component the component to configure.
* @param rememberPreviousTab if true, the previous tab will be remembered and used for the new dialog
*/
public static void showDialog(Window parent, OpenRocketDocument document, RocketComponent component, boolean rememberPreviousTab) {
ComponentConfigDialog.showDialog(parent, document, component, rememberPreviousTab, true);
}
/**
* A singleton configuration dialog. Will create and show a new dialog if one has not
* previously been used, or update the dialog and show it if a previous one exists.

View File

@ -81,6 +81,7 @@ public class FreeformFinSetConfig extends FinSetConfig {
private Point dragPoint = null;
private FinPointFigure figure = null;
private ScaleScrollPane figurePane = null;
private ScaleSelector selector;
public FreeformFinSetConfig(OpenRocketDocument d, RocketComponent component, JDialog parent) {
@ -219,7 +220,7 @@ public class FreeformFinSetConfig extends FinSetConfig {
// Create the figure
figure = new FinPointFigure(finset);
ScaleScrollPane figurePane = new FinPointScrollPane( figure);
figurePane = new FinPointScrollPane( figure);
// Create the table
tableModel = new FinPointTableModel();
@ -392,9 +393,10 @@ public class FreeformFinSetConfig extends FinSetConfig {
}
figure.updateFigure();
}
revalidate();
repaint();
if (figurePane != null) {
figurePane.revalidate();
}
}
private class FinPointScrollPane extends ScaleScrollPane {
@ -408,8 +410,6 @@ public class FreeformFinSetConfig extends FinSetConfig {
@Override
public void mousePressed(MouseEvent event) {
int mods = event.getModifiersEx();
final FreeformFinSet finset = (FreeformFinSet) component;
final int pressIndex = getPoint(event);

View File

@ -64,7 +64,6 @@ public class InnerTubeConfig extends RocketComponentConfig {
super(d, c, parent);
//// General and General properties
JPanel rightPanel = new JPanel(new MigLayout());
JPanel panel = new JPanel(new MigLayout("gap rel unrel", "[][65lp::][30lp::][]", ""));
DoubleModel m;
@ -86,7 +85,7 @@ public class InnerTubeConfig extends RocketComponentConfig {
panel.add(spin, "growx");
panel.add(new UnitSelector(od), "growx");
panel.add(new BasicSlider(od.getSliderModel(0, 0.04, 0.2)), "w 100lp, wrap");
panel.add(new BasicSlider(od.getSliderModel(0, 0.04, 0.2)), "wmin 100lp, growx, wrap");
if (od.isAutomaticAvailable()) {
JCheckBox check = new JCheckBox(od.getAutomaticAction());
@ -106,7 +105,7 @@ public class InnerTubeConfig extends RocketComponentConfig {
panel.add(spin, "growx");
panel.add(new UnitSelector(m), "growx");
panel.add(new BasicSlider(m.getSliderModel(new DoubleModel(0), od)), "w 100lp, wrap");
panel.add(new BasicSlider(m.getSliderModel(new DoubleModel(0), od)), "wmin 100lp, growx, wrap");
if (m.isAutomaticAvailable()) {
JCheckBox check = new JCheckBox(m.getAutomaticAction());
@ -127,7 +126,7 @@ public class InnerTubeConfig extends RocketComponentConfig {
panel.add(spin, "growx");
panel.add(new UnitSelector(m), "growx");
panel.add(new BasicSlider(m.getSliderModel(0, 0.01)), "w 100lp, wrap");
panel.add(new BasicSlider(m.getSliderModel(0, 0.01)), "wmin 100lp, growx, wrap");
//// Inner tube length
@ -138,14 +137,15 @@ public class InnerTubeConfig extends RocketComponentConfig {
spin = new JSpinner(m.getSpinnerModel());
spin.setEditor(new SpinnerEditor(spin));
focusElement = spin;
panel.add(spin, "growx");
panel.add(new UnitSelector(m), "growx");
panel.add(new BasicSlider(m.getSliderModel(0, 0.1, 1.0)), "w 100lp, wrap");
panel.add(new BasicSlider(m.getSliderModel(0, 0.1, 1.0)), "wmin 100lp, growx, wrap");
//// Material
panel.add(materialPanel(Material.Type.BULK),
"spanx 3, growx, wrap 15lp");
"spanx 4, growx, wrap 15lp");
//// Right side of panel ----
@ -174,7 +174,7 @@ public class InnerTubeConfig extends RocketComponentConfig {
panel2.add(new BasicSlider(m.getSliderModel(
new DoubleModel(component.getParent(), "Length", -1.0, UnitGroup.UNITS_NONE),
new DoubleModel(component.getParent(), "Length"))),
"w 100lp, wrap");
"wmin 100lp, growx, wrap");

View File

@ -45,6 +45,7 @@ public class LaunchLugConfig extends RocketComponentConfig {
JSpinner spin = new JSpinner(m.getSpinnerModel());
spin.setEditor(new SpinnerEditor(spin));
focusElement = spin;
panel.add(spin, "growx");
panel.add(new UnitSelector(m), "growx");

View File

@ -138,6 +138,7 @@ public class MassComponentConfig extends RocketComponentConfig {
m = new DoubleModel(component, "AxialOffset", UnitGroup.UNITS_LENGTH);
spin = new JSpinner(m.getSpinnerModel());
spin.setEditor(new SpinnerEditor(spin));
focusElement = spin;
panel2.add(spin, "growx");
panel2.add(new UnitSelector(m), "growx");

View File

@ -163,6 +163,7 @@ public class ParachuteConfig extends RecoveryDeviceConfig {
m = new DoubleModel(component, "AxialOffset", UnitGroup.UNITS_LENGTH);
spin = new JSpinner(m.getSpinnerModel());
spin.setEditor(new SpinnerEditor(spin));
focusElement = spin;
panel.add(spin, "growx");
panel.add(new UnitSelector(m), "growx");

View File

@ -92,6 +92,7 @@ public class RailButtonConfig extends RocketComponentConfig {
DoubleModel offsetModel = new DoubleModel(component, "AxialOffset", UnitGroup.UNITS_LENGTH);
JSpinner offsetSpinner = new JSpinner(offsetModel.getSpinnerModel());
offsetSpinner.setEditor(new SpinnerEditor(offsetSpinner));
focusElement = offsetSpinner;
panel.add(offsetSpinner, "growx");
panel.add(new UnitSelector(offsetModel), "growx");
panel.add(new BasicSlider(offsetModel.getSliderModel(

View File

@ -20,6 +20,7 @@ import net.sf.openrocket.l10n.Translator;
import net.sf.openrocket.material.Material;
import net.sf.openrocket.rocketcomponent.EngineBlock;
import net.sf.openrocket.rocketcomponent.RocketComponent;
import net.sf.openrocket.rocketcomponent.ThicknessRingComponent;
import net.sf.openrocket.rocketcomponent.position.AxialMethod;
import net.sf.openrocket.startup.Application;
import net.sf.openrocket.unit.UnitGroup;
@ -116,6 +117,9 @@ public class RingComponentConfig extends RocketComponentConfig {
spin = new JSpinner(m.getSpinnerModel());
spin.setEditor(new SpinnerEditor(spin));
if (component instanceof ThicknessRingComponent) {
focusElement = spin;
}
panel.add(spin, "growx");
panel.add(new UnitSelector(m), "growx");
@ -139,6 +143,9 @@ public class RingComponentConfig extends RocketComponentConfig {
m = new DoubleModel(component, "AxialOffset", UnitGroup.UNITS_LENGTH);
spin = new JSpinner(m.getSpinnerModel());
spin.setEditor(new SpinnerEditor(spin));
if (!(component instanceof ThicknessRingComponent)) {
focusElement = spin;
}
panel.add(spin, "growx");
panel.add(new UnitSelector(m), "growx");

View File

@ -22,8 +22,10 @@ import javax.swing.JSpinner;
import javax.swing.JTabbedPane;
import javax.swing.JTextArea;
import javax.swing.JTextField;
import javax.swing.SwingUtilities;
import net.miginfocom.swing.MigLayout;
import net.sf.openrocket.database.ComponentPresetDatabase;
import net.sf.openrocket.document.OpenRocketDocument;
import net.sf.openrocket.gui.SpinnerEditor;
import net.sf.openrocket.gui.adaptors.BooleanModel;
@ -36,6 +38,7 @@ import net.sf.openrocket.gui.components.BasicSlider;
import net.sf.openrocket.gui.components.StyledLabel;
import net.sf.openrocket.gui.components.StyledLabel.Style;
import net.sf.openrocket.gui.components.UnitSelector;
import net.sf.openrocket.gui.dialogs.preset.ComponentPresetChooserDialog;
import net.sf.openrocket.gui.util.GUIUtil;
import net.sf.openrocket.gui.widgets.SelectColorButton;
import net.sf.openrocket.l10n.Translator;
@ -61,6 +64,7 @@ public class RocketComponentConfig extends JPanel {
private JComboBox<?> presetComboBox;
private PresetModel presetModel;
protected Component focusElement = null; // Element that will be focused on after a preset is selected
protected final JTextField componentNameField;
protected JTextArea commentTextArea;
@ -100,7 +104,7 @@ public class RocketComponentConfig extends JPanel {
//// Component name:
JLabel label = new JLabel(trans.get("RocketCompCfg.lbl.Componentname"));
//// The component name.
label.setToolTipText(trans.get("RocketCompCfg.ttip.Thecomponentname"));
label.setToolTipText(trans.get("RocketCompCfg.lbl.Componentname.ttip"));
this.add(label, "spanx, height 32!, split");
componentNameField = new JTextField(15);
@ -108,15 +112,27 @@ public class RocketComponentConfig extends JPanel {
componentNameField.addActionListener(textFieldListener);
componentNameField.addFocusListener(textFieldListener);
//// The component name.
componentNameField.setToolTipText(trans.get("RocketCompCfg.ttip.Thecomponentname"));
componentNameField.setToolTipText(trans.get("RocketCompCfg.lbl.Componentname.ttip"));
this.add(componentNameField, "growx");
if (allSameType && component.getPresetType() != null) {
// If the component supports a preset, show the preset selection box.
presetModel = new PresetModel(this, document, component);
presetComboBox = new JComboBox(presetModel);
presetComboBox.setMaximumRowCount(25);
presetComboBox.setEditable(false);
this.add(presetComboBox, "");
presetComboBox.setToolTipText(trans.get("PresetModel.combo.ttip"));
this.add(presetComboBox, "growx 110");
final JButton selectPreset = new SelectColorButton(trans.get("PresetModel.lbl.partsLib"));
selectPreset.setToolTipText(trans.get("PresetModel.lbl.partsLib.ttip"));
selectPreset.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
selectPreset();
}
});
this.add(selectPreset);
}
tabbedPane = new JTabbedPane();
@ -124,17 +140,17 @@ public class RocketComponentConfig extends JPanel {
//// Override and Mass and CG override options
tabbedPane.addTab(trans.get("RocketCompCfg.tab.Override"), null, overrideTab(),
trans.get("RocketCompCfg.tab.MassandCGoverride"));
trans.get("RocketCompCfg.tab.Override.ttip"));
if (allMassive) {
//// Appearance options
appearancePanel = new AppearancePanel(document, component, parent);
tabbedPane.addTab(trans.get("RocketCompCfg.tab.Appearance"), null, appearancePanel,
"Appearance Tool Tip");
trans.get("RocketCompCfg.tab.Appearance.ttip"));
}
//// Comment and Specify a comment for the component
tabbedPane.addTab(trans.get("RocketCompCfg.tab.Comment"), null, commentTab(),
trans.get("RocketCompCfg.tab.Specifyacomment"));
trans.get("RocketCompCfg.tab.Comment.ttip"));
addButtons();
@ -241,6 +257,24 @@ public class RocketComponentConfig extends JPanel {
}
}
private void selectPreset() {
SwingUtilities.invokeLater(new Runnable() {
@Override
public void run() {
if (presetComboBox == null || presetModel == null) return;
((ComponentPresetDatabase) Application.getComponentPresetDao()).addDatabaseListener(presetModel);
ComponentPresetChooserDialog dialog =
new ComponentPresetChooserDialog(SwingUtilities.getWindowAncestor(RocketComponentConfig.this), component);
dialog.setVisible(true);
ComponentPreset preset = dialog.getSelectedComponentPreset();
if (preset != null) {
presetModel.setSelectedItem(preset);
}
((ComponentPresetDatabase) Application.getComponentPresetDao()).removeChangeListener(presetModel);
}
});
}
public void clearConfigListeners() {
if (appearancePanel != null) {
appearancePanel.clearConfigListeners();
@ -702,6 +736,24 @@ public class RocketComponentConfig extends JPanel {
}
}
}
/**
* Requests focus for the focus element that should be active after a preset is selected.
*/
public void setFocusElement() {
if (focusElement != null) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
if (focusElement instanceof JSpinner) {
SpinnerEditor ed = (SpinnerEditor) ((JSpinner)focusElement).getEditor();
ed.getTextField().requestFocusInWindow();
} else {
focusElement.requestFocusInWindow();
}
}
});
}
}
protected void register(Invalidatable model) {

View File

@ -80,6 +80,7 @@ public class ShockCordConfig extends RocketComponentConfig {
m = new DoubleModel(component, "AxialOffset", UnitGroup.UNITS_LENGTH);
spin = new JSpinner(m.getSpinnerModel());
spin.setEditor(new SpinnerEditor(spin));
focusElement = spin;
panel2.add(spin, "growx");
panel2.add(new UnitSelector(m), "growx");

View File

@ -149,6 +149,7 @@ public class StreamerConfig extends RecoveryDeviceConfig {
m = new DoubleModel(component, "AxialOffset", UnitGroup.UNITS_LENGTH);
spin = new JSpinner(m.getSpinnerModel());
spin.setEditor(new SpinnerEditor(spin));
focusElement = spin;
panel.add(spin, "growx");
panel.add(new UnitSelector(m), "growx");

View File

@ -54,6 +54,7 @@ public class TubeFinSetConfig extends RocketComponentConfig {
spin = new JSpinner(m.getSpinnerModel());
spin.setEditor(new SpinnerEditor(spin));
focusElement = spin;
panel.add(spin, "growx");
panel.add(new UnitSelector(m), "growx");

View File

@ -346,7 +346,7 @@ public class ScaleDialog extends JDialog {
panel.add(selectionOption, "growx, wrap para*2");
// Select the 'scale component / scale selection and all subcomponents' if a component is selected
if (selection != null && selection.size() > 0) {
if (options.size() > 1 && selection != null && selection.size() > 0) {
boolean entireRocket = false; // Flag to scale entire rocket
for (RocketComponent component : selection) {
if (component instanceof Rocket || (component instanceof AxialStage && !(component instanceof ParallelStage))) {

View File

@ -11,6 +11,7 @@ import javax.swing.JSpinner;
import net.miginfocom.swing.MigLayout;
import net.sf.openrocket.gui.SpinnerEditor;
import net.sf.openrocket.gui.adaptors.DoubleModel;
import net.sf.openrocket.gui.main.BasicFrame;
import net.sf.openrocket.startup.Preferences;
import net.sf.openrocket.unit.UnitGroup;
@ -93,7 +94,6 @@ public class DesignPreferencesPanel extends PreferencesPanel {
// // Always open leftmost tab when opening a component edit dialog
final JCheckBox alwaysOpenLeftmostTab = new JCheckBox(
trans.get("pref.dlg.checkbox.AlwaysOpenLeftmost"));
alwaysOpenLeftmostTab.setSelected(preferences.isAlwaysOpenLeftmostTab());
alwaysOpenLeftmostTab.setToolTipText(trans.get("pref.dlg.checkbox.AlwaysOpenLeftmost.ttip"));
alwaysOpenLeftmostTab.addActionListener(new ActionListener() {
@ -103,7 +103,7 @@ public class DesignPreferencesPanel extends PreferencesPanel {
.isSelected());
}
});
this.add(alwaysOpenLeftmostTab, "wrap, growx, span 2");
this.add(alwaysOpenLeftmostTab, "wrap, growx, spanx");
// // Update flight estimates in the design window
final JCheckBox updateEstimates = new JCheckBox(
@ -117,5 +117,23 @@ public class DesignPreferencesPanel extends PreferencesPanel {
}
});
this.add(updateEstimates, "wrap, growx, sg combos ");
// // Only show pod set/booster markers when they are selected
final JCheckBox showMarkers = new JCheckBox(
trans.get("pref.dlg.checkbox.Markers"));
showMarkers.setToolTipText(trans.get("pref.dlg.checkbox.Markers.ttip"));
showMarkers.setSelected(preferences.isShowMarkers());
showMarkers.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
preferences.setShowMarkers(showMarkers
.isSelected());
// Update all BasicFrame rocket panel figures because it can change due to the preference change
for (BasicFrame frame : BasicFrame.getAllFrames()) {
frame.getRocketPanel().updateFigures();
}
}
});
this.add(showMarkers, "wrap, growx, spanx");
}
}

View File

@ -7,6 +7,7 @@ import com.jogamp.opengl.fixedfunc.GLMatrixFunc;
import com.jogamp.opengl.glu.GLU;
import com.jogamp.opengl.glu.GLUquadric;
import net.sf.openrocket.rocketcomponent.InnerTube;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@ -98,6 +99,8 @@ public class ComponentRenderer {
if (c instanceof BodyTube) {
renderTube(gl, (BodyTube) c, which);
} else if (c instanceof InnerTube) {
renderTube(gl, (InnerTube) c, which);
} else if (c instanceof LaunchLug) {
renderLug(gl, (LaunchLug) c, which);
} else if ( c instanceof RailButton ){
@ -257,6 +260,10 @@ public class ComponentRenderer {
renderTube(gl, which, t.getOuterRadius(), t.getInnerRadius(), t.getLength());
}
private void renderTube(GL2 gl, InnerTube t, Surface which) {
renderTube(gl, which, t.getOuterRadius(), t.getInnerRadius(), t.getLength());
}
private void renderRing(GL2 gl, RingComponent r) {
gl.glRotated(90, 0, 1.0, 0);

View File

@ -108,7 +108,7 @@ public class PhotoFrame extends JFrame {
settings = new JDialog(this, trans.get("PhotoSettingsConfig.title")) {
{
setContentPane(new PhotoSettingsConfig(p));
setContentPane(new PhotoSettingsConfig(p, document));
pack();
this.setLocationByPlatform(true);
GUIUtil.rememberWindowSize(this);

View File

@ -36,7 +36,7 @@ public class PhotoSettings extends AbstractChangeSource implements FlameSettings
private double exhaustScale = 1.0;
private double flameAspectRatio = 1.0;
private double sparkConcentration = 0;
private double sparkConcentration = 0.2;
private double sparkWeight = 0;
private Sky sky = Mountains.instance;
@ -278,5 +278,6 @@ public class PhotoSettings extends AbstractChangeSource implements FlameSettings
public void setSmokeOpacity(double smokeOpacity) {
this.smokeOpacity = smokeOpacity;
setSmokeAlpha(smokeOpacity);
}
}

View File

@ -25,8 +25,10 @@ import javax.swing.event.ChangeListener;
import com.jogamp.opengl.GL2;
import net.miginfocom.swing.MigLayout;
import net.sf.openrocket.document.OpenRocketDocument;
import net.sf.openrocket.gui.adaptors.BooleanModel;
import net.sf.openrocket.gui.adaptors.DoubleModel;
import net.sf.openrocket.gui.components.BasicSlider;
import net.sf.openrocket.gui.components.ColorIcon;
import net.sf.openrocket.gui.components.EditableSpinner;
import net.sf.openrocket.gui.components.StyledLabel;
@ -125,7 +127,7 @@ public class PhotoSettingsConfig extends JTabbedPane {
}
}
public PhotoSettingsConfig(PhotoSettings p) {
public PhotoSettingsConfig(PhotoSettings p, OpenRocketDocument document) {
super();
setPreferredSize(new Dimension(240, 320));
@ -170,25 +172,29 @@ public class PhotoSettingsConfig extends JTabbedPane {
add(new JLabel(trans.get("PhotoSettingsConfig.lbl.pitch")));
DoubleModel pitchModel = new DoubleModel(p, "Pitch", UnitGroup.UNITS_ANGLE);
add(new EditableSpinner(pitchModel.getSpinnerModel()), "growx");
add(new UnitSelector(pitchModel), "pushx, left, wrap");
add(new UnitSelector(pitchModel), "growx");
add(new BasicSlider(pitchModel.getSliderModel(0, 2 * Math.PI)), "pushx, left, wrap");
/// Yaw
add(new JLabel(trans.get("PhotoSettingsConfig.lbl.yaw")));
DoubleModel yawModel = new DoubleModel(p, "Yaw", UnitGroup.UNITS_ANGLE);
add(new EditableSpinner(yawModel.getSpinnerModel()), "growx");
add(new UnitSelector(yawModel), "wrap");
add(new UnitSelector(yawModel), "growx");
add(new BasicSlider(yawModel.getSliderModel(0, 2 * Math.PI)), "wrap");
/// Roll
add(new JLabel(trans.get("PhotoSettingsConfig.lbl.roll")));
DoubleModel rollModel = new DoubleModel(p, "Roll", UnitGroup.UNITS_ANGLE);
add(new EditableSpinner(rollModel.getSpinnerModel()), "growx");
add(new UnitSelector(rollModel), "wrap");
add(new UnitSelector(rollModel), "growx");
add(new BasicSlider(rollModel.getSliderModel(0, 2 * Math.PI)), "wrap");
/// Advance
add(new JLabel(trans.get("PhotoSettingsConfig.lbl.advance")));
DoubleModel advanceModel = new DoubleModel(p, "Advance", UnitGroup.UNITS_LENGTH);
add(new EditableSpinner(advanceModel.getSpinnerModel()), "growx");
add(new UnitSelector(advanceModel), "wrap");
add(new UnitSelector(advanceModel), "growx");
add(new BasicSlider(advanceModel.getSliderModel(-document.getRocket().getLength(), document.getRocket().getLength())), "wrap");
// Camera
add(new StyledLabel(trans.get("PhotoSettingsConfig.lbl.camera"), Style.BOLD), "split, gapright para, span");
@ -198,25 +204,29 @@ public class PhotoSettingsConfig extends JTabbedPane {
add(new JLabel(trans.get("PhotoSettingsConfig.lbl.vAz")));
DoubleModel viewAzModel = new DoubleModel(p, "ViewAz", UnitGroup.UNITS_ANGLE);
add(new EditableSpinner(viewAzModel.getSpinnerModel()), "growx");
add(new UnitSelector(viewAzModel), "wrap");
add(new UnitSelector(viewAzModel), "growx");
add(new BasicSlider(viewAzModel.getSliderModel(0, 2 * Math.PI)), "wrap");
/// View altitude
add(new JLabel(trans.get("PhotoSettingsConfig.lbl.vAlt")));
DoubleModel viewAltModle = new DoubleModel(p, "ViewAlt", UnitGroup.UNITS_ANGLE);
DoubleModel viewAltModle = new DoubleModel(p, "ViewAlt", UnitGroup.UNITS_ANGLE, -Math.PI / 2, Math.PI / 2);
add(new EditableSpinner(viewAltModle.getSpinnerModel()), "growx");
add(new UnitSelector(viewAltModle), "wrap");
add(new UnitSelector(viewAltModle), "growx");
add(new BasicSlider(viewAltModle.getSliderModel(-Math.PI / 2, Math.PI / 2)), "wrap");
/// View distance
add(new JLabel(trans.get("PhotoSettingsConfig.lbl.vDist")));
DoubleModel viewDistanceModel = new DoubleModel(p, "ViewDistance", UnitGroup.UNITS_LENGTH);
add(new EditableSpinner(viewDistanceModel.getSpinnerModel()), "growx");
add(new UnitSelector(viewDistanceModel), "wrap");
add(new UnitSelector(viewDistanceModel), "growx");
add(new BasicSlider(viewDistanceModel.getSliderModel(0, 2 * document.getRocket().getLength())), "wrap");
/// FoV
add(new JLabel(trans.get("PhotoSettingsConfig.lbl.fov")));
DoubleModel fovModel = new DoubleModel(p, "Fov", UnitGroup.UNITS_ANGLE);
DoubleModel fovModel = new DoubleModel(p, "Fov", UnitGroup.UNITS_ANGLE, Math.PI * 57.3/180, Math.PI * 160/180);
add(new EditableSpinner(fovModel.getSpinnerModel()), "growx");
add(new UnitSelector(fovModel), "wrap");
add(new UnitSelector(fovModel), "growx");
add(new BasicSlider(fovModel.getSliderModel(Math.PI * 57.3/180, Math.PI * 160/180)), "wrap");
}
});
@ -232,19 +242,24 @@ public class PhotoSettingsConfig extends JTabbedPane {
/// Ambiance
add(new JLabel(trans.get("PhotoSettingsConfig.lbl.amb")));
DoubleModel ambianceModel = new DoubleModel(p, "Ambiance", 100, UnitGroup.UNITS_NONE, 0, 100);
add(new EditableSpinner(ambianceModel.getSpinnerModel()), "wrap");
DoubleModel ambianceModel = new DoubleModel(p, "Ambiance", UnitGroup.UNITS_RELATIVE, 0, 1);
add(new EditableSpinner(ambianceModel.getSpinnerModel()), "growx, split 2");
add(new UnitSelector(ambianceModel));
add(new BasicSlider(ambianceModel.getSliderModel(0, 1)), "pushx, left, wrap");
/// Light azimuth
add(new JLabel(trans.get("PhotoSettingsConfig.lbl.lightAz")));
DoubleModel lightAzModel = new DoubleModel(p, "LightAz", UnitGroup.UNITS_ANGLE);
add(new EditableSpinner(lightAzModel.getSpinnerModel()), "split 2");
add(new UnitSelector(lightAzModel), "pushx, left, wrap");
add(new EditableSpinner(lightAzModel.getSpinnerModel()), "growx, split 2");
add(new UnitSelector(lightAzModel));
add(new BasicSlider(lightAzModel.getSliderModel(-Math.PI, Math.PI)), "wrap");
/// Light altitude
add(new JLabel(trans.get("PhotoSettingsConfig.lbl.lightAlt")));
DoubleModel lightAltModle = new DoubleModel(p, "LightAlt", UnitGroup.UNITS_ANGLE);
add(new EditableSpinner(lightAltModle.getSpinnerModel()), "wrap");
DoubleModel lightAltModle = new DoubleModel(p, "LightAlt", UnitGroup.UNITS_ANGLE, -Math.PI / 2, Math.PI / 2);
add(new EditableSpinner(lightAltModle.getSpinnerModel()), "growx, split 2");
add(new UnitSelector(lightAltModle));
add(new BasicSlider(lightAltModle.getSliderModel(-Math.PI / 2, Math.PI / 2)), "wrap");
// Sky
add(new StyledLabel(trans.get("PhotoSettingsConfig.lbl.sky"), Style.BOLD), "split, span, gapright para");
@ -292,7 +307,7 @@ public class PhotoSettingsConfig extends JTabbedPane {
setSelectedItem(noSky);
}
}
}, "wrap");
}, "spanx, wrap");
/// Image credit
final JLabel creditLabel = new JLabel(trans.get("PhotoSettingsConfig.lbl.skyCredit"));
@ -304,7 +319,7 @@ public class PhotoSettingsConfig extends JTabbedPane {
credit.setOpaque(false);
credit.setFocusable(false);
credit.setFont(creditLabel.getFont());
add(credit);
add(credit, "spanx");
final StateChangeListener skyChange = new StateChangeListener() {
@Override
@ -332,22 +347,28 @@ public class PhotoSettingsConfig extends JTabbedPane {
/// Smoke
add(new JLabel(trans.get("PhotoSettingsConfig.lbl.smoke")));
BooleanModel smokeModel = new BooleanModel(p, "Smoke");
add(new JCheckBox(smokeModel), "split 2, w 15");
add(new JCheckBox(smokeModel), "split 2, spanx");
add(smokeColorButton, "pushx, left, wrap");
add(smokeColorButton, "wrap");
smokeModel.addEnableComponent(smokeColorButton);
/// Smoke opacity
add(new JLabel(trans.get("PhotoSettingsConfig.lbl.smokeOpacity")));
DoubleModel smokeOpacityModel = new DoubleModel(p, "SmokeOpacity", 100, UnitGroup.UNITS_NONE, 0, 100);
DoubleModel smokeOpacityModel = new DoubleModel(p, "SmokeOpacity", UnitGroup.UNITS_RELATIVE, 0, 1);
EditableSpinner opacitySpinner = new EditableSpinner(smokeOpacityModel.getSpinnerModel());
add(opacitySpinner, "wrap");
UnitSelector opacitySelector = new UnitSelector(smokeOpacityModel);
BasicSlider opacitySlider = new BasicSlider(smokeOpacityModel.getSliderModel(0, 1));
add(opacitySpinner, "growx");
add(opacitySelector);
add(opacitySlider, "wrap");
smokeModel.addEnableComponent(opacitySpinner);
smokeModel.addEnableComponent(opacitySelector);
smokeModel.addEnableComponent(opacitySlider);
/// Flame
add(new JLabel(trans.get("PhotoSettingsConfig.lbl.flame")));
BooleanModel fireModel = new BooleanModel(p, "Flame");
add(new JCheckBox(fireModel), "split 2, w 15");
add(new JCheckBox(fireModel), "split 2, spanx");
add(flameColorButton, "wrap");
fireModel.addEnableComponent(flameColorButton);
@ -357,8 +378,11 @@ public class PhotoSettingsConfig extends JTabbedPane {
DoubleModel flameAspectModel = new DoubleModel(p, "FlameAspectRatio", 100, UnitGroup.UNITS_NONE, 25,
250);
EditableSpinner flameAspectSpinner = new EditableSpinner(flameAspectModel.getSpinnerModel());
add(flameAspectSpinner, "wrap");
BasicSlider flameAspectSlider = new BasicSlider(flameAspectModel.getSliderModel(25, 250));
add(flameAspectSpinner, "growx");
add(flameAspectSlider, "skip 1, wrap");
fireModel.addEnableComponent(flameAspectSpinner);
fireModel.addEnableComponent(flameAspectSlider);
/// Sparks
add(new JLabel(trans.get("PhotoSettingsConfig.lbl.sparks")));
@ -369,23 +393,36 @@ public class PhotoSettingsConfig extends JTabbedPane {
/// Sparks concentration
add(new JLabel(trans.get("PhotoSettingsConfig.lbl.sparkConcentration")));
DoubleModel sparkConcentrationModel = new DoubleModel(p, "SparkConcentration", 100,
UnitGroup.UNITS_NONE, 0, 100);
DoubleModel sparkConcentrationModel = new DoubleModel(p, "SparkConcentration",
UnitGroup.UNITS_RELATIVE, 0, 1);
EditableSpinner sparkConcentrationSpinner = new EditableSpinner(sparkConcentrationModel.getSpinnerModel());
add(sparkConcentrationSpinner, "wrap");
UnitSelector sparkConcentrationSelector = new UnitSelector(sparkConcentrationModel);
BasicSlider sparkConcentrationSlider = new BasicSlider(sparkConcentrationModel.getSliderModel(0, 1));
add(sparkConcentrationSpinner, "growx");
add(sparkConcentrationSelector);
add(sparkConcentrationSlider, "wrap");
sparksModel.addEnableComponent(sparkConcentrationSpinner);
sparksModel.addEnableComponent(sparkConcentrationSelector);
sparksModel.addEnableComponent(sparkConcentrationSlider);
/// Spark weight
add(new JLabel(trans.get("PhotoSettingsConfig.lbl.sparkWeight")));
DoubleModel sparkWeightModel = new DoubleModel(p, "SparkWeight", 100, UnitGroup.UNITS_NONE, 0, 100);
DoubleModel sparkWeightModel = new DoubleModel(p, "SparkWeight", UnitGroup.UNITS_RELATIVE, 0, 1);
EditableSpinner sparkWeightSpinner = new EditableSpinner(sparkWeightModel.getSpinnerModel());
add(sparkWeightSpinner, "wrap");
UnitSelector sparkWeightSelector = new UnitSelector(sparkWeightModel);
BasicSlider sparkWeightSlider = new BasicSlider(sparkWeightModel.getSliderModel(0, 1));
add(sparkWeightSpinner, "growx");
add(sparkWeightSelector);
add(sparkWeightSlider, "wrap");
sparksModel.addEnableComponent(sparkWeightSpinner);
sparksModel.addEnableComponent(sparkWeightSelector);
sparksModel.addEnableComponent(sparkWeightSlider);
/// Exhaust scale
add(new JLabel(trans.get("PhotoSettingsConfig.lbl.exhaustScale")));
DoubleModel exhaustScaleModel = new DoubleModel(p, "ExhaustScale", 100, UnitGroup.UNITS_NONE, 0, 1000);
add(new EditableSpinner(exhaustScaleModel.getSpinnerModel()), "wrap");
add(new EditableSpinner(exhaustScaleModel.getSpinnerModel()), "growx");
add(new BasicSlider(exhaustScaleModel.getSliderModel(0, 1000)), "skip 1, wrap");
// Effects
add(new StyledLabel(trans.get("PhotoSettingsConfig.lbl.effects"), Style.BOLD), "split, span, gapright para");

View File

@ -41,7 +41,7 @@ public class RocketInfo implements FigureElement {
private final Caret cpCaret = new CPCaret(0,0);
private final Caret cgCaret = new CGCaret(0,0);
private final UnitGroup stabilityUnits;
private UnitGroup stabilityUnits;
private FlightConfiguration configuration;
private double cg = 0, cp = 0;
@ -459,5 +459,6 @@ public class RocketInfo implements FigureElement {
public void setCurrentConfig(FlightConfiguration newConfig) {
this.configuration = newConfig;
this.stabilityUnits = UnitGroup.stabilityUnits(newConfig);
}
}

View File

@ -19,6 +19,7 @@ import java.net.URL;
import java.net.URLDecoder;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import java.util.concurrent.ExecutionException;
@ -116,7 +117,8 @@ public class BasicFrame extends JFrame {
* List of currently open frames. When the list goes empty
* it is time to exit the application.
*/
private static final ArrayList<BasicFrame> frames = new ArrayList<BasicFrame>();
private static final List<BasicFrame> frames = new ArrayList<BasicFrame>();
private static BasicFrame startupFrame = null; // the frame that was created at startup
/**
@ -300,23 +302,28 @@ public class BasicFrame extends JFrame {
componentSelectionModel.addTreeSelectionListener(new TreeSelectionListener() {
@Override
public void valueChanged(TreeSelectionEvent e) {
TreePath selPath = e.getNewLeadSelectionPath();
if (selPath == null) return;
RocketComponent c = (RocketComponent) selPath.getLastPathComponent();
if (tree == null || tree.getSelectionPaths() == null || tree.getSelectionPaths().length == 0
|| rocketpanel == null) return;
if (c instanceof AxialStage || c instanceof Rocket || c instanceof PodSet) {
if (rocketpanel == null) return;
List<RocketComponent> children = new LinkedList<>();
for (RocketComponent child : c) {
children.add(child);
// Get all the components that need to be selected = currently selected components + children of stages/boosters/podsets
List<RocketComponent> children = new ArrayList<>(Arrays.asList(rocketpanel.getFigure().getSelection()));
for (TreePath p : tree.getSelectionPaths()) {
if (p != null) {
RocketComponent c = (RocketComponent) p.getLastPathComponent();
if (c instanceof AxialStage || c instanceof Rocket || c instanceof PodSet) {
Iterator<RocketComponent> iter = c.iterator(false);
while (iter.hasNext()) {
RocketComponent child = iter.next();
children.add(child);
}
}
}
}
// Select all the child components
if (rocketpanel.getFigure() != null && rocketpanel.getFigure3d() != null) {
rocketpanel.getFigure().setSelection(children.toArray(new RocketComponent[0]));
rocketpanel.getFigure3d().setSelection(children.toArray(new RocketComponent[0]));
}
// Select all the child components
if (rocketpanel.getFigure() != null && rocketpanel.getFigure3d() != null) {
rocketpanel.getFigure().setSelection(children.toArray(new RocketComponent[0]));
rocketpanel.getFigure3d().setSelection(children.toArray(new RocketComponent[0]));
}
}
});
@ -483,6 +490,10 @@ public class BasicFrame extends JFrame {
return result;
}
public RocketPanel getRocketPanel() {
return rocketpanel;
}
/**
* Creates the menu for the window.
*/
@ -1225,6 +1236,19 @@ public class BasicFrame extends JFrame {
return menu;
}
/**
* Return the frame that was created at the application's startup.
*/
public static BasicFrame getStartupFrame() {
return startupFrame;
}
/**
* Set the frame that is created at the application's startup.
*/
public static void setStartupFrame(BasicFrame startupFrame) {
BasicFrame.startupFrame = startupFrame;
}
/**
* Select the tab on the main pane.
@ -1267,7 +1291,7 @@ public class BasicFrame extends JFrame {
for (File file : files) {
log.info("Opening file: " + file);
if (open(file, parent)) {
if (open(file, parent) != null) {
MRUDesignFile opts = MRUDesignFile.getInstance();
opts.addFile(file.getAbsolutePath());
}
@ -1297,7 +1321,7 @@ public class BasicFrame extends JFrame {
for (File file : files) {
log.info("Opening file: " + file);
if (open(file, this)) {
if (open(file, this) != null) {
MRUDesignFile opts = MRUDesignFile.getInstance();
opts.addFile(file.getAbsolutePath());
}
@ -1367,9 +1391,9 @@ public class BasicFrame extends JFrame {
*
* @param file the file to open.
* @param parent the parent component for which a progress dialog is opened.
* @return whether the file was successfully loaded and opened.
* @return the BasicFrame that was created, or null if not created successfully.
*/
public static boolean open(File file, Window parent) {
public static BasicFrame open(File file, Window parent) {
OpenFileWorker worker = new OpenFileWorker(file);
return open(worker, file.getName(), parent, false);
}
@ -1382,15 +1406,15 @@ public class BasicFrame extends JFrame {
* @param displayName the file name to display in dialogs.
* @param parent
* @param openRocketConfigDialog if true, will open the configuration dialog of the rocket. This is useful for examples.
* @return
* @return the BasicFrame that was created, or null if not created successfully.
*/
private static boolean open(OpenFileWorker worker, String displayName, Window parent, boolean openRocketConfigDialog) {
private static BasicFrame open(OpenFileWorker worker, String displayName, Window parent, boolean openRocketConfigDialog) {
//// Open the file in a Swing worker thread
log.info("Starting OpenFileWorker");
if (!SwingWorkerDialog.runWorker(parent, "Opening file", "Reading " + displayName + "...", worker)) {
// // User cancelled the operation
log.info("User cancelled the OpenFileWorker");
return false;
return null;
}
//// Handle the document
@ -1409,7 +1433,7 @@ public class BasicFrame extends JFrame {
JOptionPane.showMessageDialog(parent,
"File not found: " + displayName,
"Error opening file", JOptionPane.ERROR_MESSAGE);
return false;
return null;
} else if (cause instanceof RocketLoadException) {
@ -1418,7 +1442,7 @@ public class BasicFrame extends JFrame {
"Unable to open file '" + displayName + "': "
+ cause.getMessage(),
"Error opening file", JOptionPane.ERROR_MESSAGE);
return false;
return null;
} else {
@ -1462,7 +1486,7 @@ public class BasicFrame extends JFrame {
ComponentConfigDialog.showDialog(frame, doc, doc.getRocket());
}
return true;
return frame;
}
@ -1768,24 +1792,27 @@ public class BasicFrame extends JFrame {
/**
* Opens a new design file or the last design file, if set in the preferences.
* Can be used for reopening the application or opening it the first time.
* @return the BasicFrame that was created
*/
public static void reopen() {
public static BasicFrame reopen() {
if (!Application.getPreferences().isAutoOpenLastDesignOnStartupEnabled()) {
BasicFrame.newAction();
return BasicFrame.newAction();
} else {
String lastFile = MRUDesignFile.getInstance().getLastEditedDesignFile();
if (lastFile != null) {
log.info("Opening last design file: " + lastFile);
if (!BasicFrame.open(new File(lastFile), null)) {
BasicFrame frame = BasicFrame.open(new File(lastFile), null);
if (frame == null) {
MRUDesignFile.getInstance().removeFile(lastFile);
BasicFrame.newAction();
return BasicFrame.newAction();
}
else {
MRUDesignFile.getInstance().addFile(lastFile);
return frame;
}
}
else {
BasicFrame.newAction();
return BasicFrame.newAction();
}
}
}
@ -1793,8 +1820,9 @@ public class BasicFrame extends JFrame {
/**
* Open a new design window with a basic rocket+stage.
* @return the BasicFrame that was created
*/
public static void newAction() {
public static BasicFrame newAction() {
log.info("New action initiated");
OpenRocketDocument doc = OpenRocketDocumentFactory.createNewRocket();
@ -1802,6 +1830,7 @@ public class BasicFrame extends JFrame {
BasicFrame frame = new BasicFrame(doc);
frame.replaceable = true;
frame.setVisible(true);
return frame;
}
@ -1865,6 +1894,13 @@ public class BasicFrame extends JFrame {
return null;
}
/**
* Return all BasicFrame instances
*/
public static List<BasicFrame> getAllFrames() {
return frames;
}
/**
* Checks whether all the BasicFrames are closed.
* @return true if all the BasicFrames are closed, false if not

View File

@ -488,7 +488,7 @@ public class ComponentAddButtons extends JPanel implements Scrollable {
}
}
ComponentConfigDialog.showDialog(parent, document, component, false);
ComponentConfigDialog.showDialog(parent, document, component, false, false);
}
}

View File

@ -73,7 +73,7 @@ public final class MRUDesignFileAction extends JMenu {
@Override
public void actionPerformed(ActionEvent e) {
String command = e.getActionCommand();
if (BasicFrame.open(new File(command), parent)) {
if (BasicFrame.open(new File(command), parent) != null) {
MRUDesignFile.getInstance().addFile(command);
}
else {

View File

@ -1,9 +1,12 @@
package net.sf.openrocket.gui.main.flightconfigpanel;
import java.awt.event.ActionEvent;
import java.awt.event.FocusEvent;
import java.awt.event.FocusListener;
import java.awt.event.KeyEvent;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.util.ArrayList;
import java.util.List;
import javax.swing.AbstractAction;
@ -162,6 +165,30 @@ public class RecoveryConfigurationPanel extends FlightConfigurablePanel<Recovery
return recoveryTable;
}
@Override
protected void installTableListener() {
super.installTableListener();
table.getColumnModel().getSelectionModel().addListSelectionListener(new ListSelectionListener() {
@Override
public void valueChanged(ListSelectionEvent e) {
updateComponentSelection(e);
}
});
table.addFocusListener(new FocusListener() {
@Override
public void focusGained(FocusEvent e) {
updateComponentSelection(new ListSelectionEvent(this, 0, 0, false));
}
@Override
public void focusLost(FocusEvent e) {
}
});
}
public void selectDeployment() {
List<RecoveryDevice> devices = getSelectedComponents();
List<FlightConfigurationId> fcIds = getSelectedConfigurationIds();
@ -239,6 +266,16 @@ public class RecoveryConfigurationPanel extends FlightConfigurablePanel<Recovery
popupMenuFull.show(e.getComponent(), e.getX(), e.getY());
}
public void updateComponentSelection(ListSelectionEvent e) {
if (e.getValueIsAdjusting() || getSelectedComponents() == null) {
return;
}
List<RocketComponent> components = new ArrayList<>(getSelectedComponents());
if (components.size() == 0) return;
flightConfigurationPanel.setSelectedComponents(components);
}
public void updateButtonState() {
boolean componentSelected = getSelectedComponent() != null;
selectDeploymentButton.setEnabled(componentSelected);

View File

@ -1,9 +1,12 @@
package net.sf.openrocket.gui.main.flightconfigpanel;
import java.awt.event.ActionEvent;
import java.awt.event.FocusEvent;
import java.awt.event.FocusListener;
import java.awt.event.KeyEvent;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.util.ArrayList;
import java.util.List;
import javax.swing.AbstractAction;
@ -27,6 +30,7 @@ import net.sf.openrocket.rocketcomponent.AxialStage;
import net.sf.openrocket.rocketcomponent.ComponentChangeEvent;
import net.sf.openrocket.rocketcomponent.FlightConfigurationId;
import net.sf.openrocket.rocketcomponent.Rocket;
import net.sf.openrocket.rocketcomponent.RocketComponent;
import net.sf.openrocket.rocketcomponent.StageSeparationConfiguration;
import net.sf.openrocket.rocketcomponent.StageSeparationConfiguration.SeparationEvent;
import net.sf.openrocket.startup.Application;
@ -170,6 +174,30 @@ public class SeparationConfigurationPanel extends FlightConfigurablePanel<AxialS
return separationTable;
}
@Override
protected void installTableListener() {
super.installTableListener();
table.getColumnModel().getSelectionModel().addListSelectionListener(new ListSelectionListener() {
@Override
public void valueChanged(ListSelectionEvent e) {
updateComponentSelection(e);
}
});
table.addFocusListener(new FocusListener() {
@Override
public void focusGained(FocusEvent e) {
updateComponentSelection(new ListSelectionEvent(this, 0, 0, false));
}
@Override
public void focusLost(FocusEvent e) {
}
});
}
public void selectSeparation() {
List<AxialStage> stages = getSelectedComponents();
List<FlightConfigurationId> fcIds = getSelectedConfigurationIds();
@ -248,6 +276,16 @@ public class SeparationConfigurationPanel extends FlightConfigurablePanel<AxialS
popupMenuFull.show(e.getComponent(), e.getX(), e.getY());
}
public void updateComponentSelection(ListSelectionEvent e) {
if (e.getValueIsAdjusting() || getSelectedComponents() == null) {
return;
}
List<RocketComponent> components = new ArrayList<>(getSelectedComponents());
if (components.size() == 0) return;
flightConfigurationPanel.setSelectedComponents(components);
}
public void updateButtonState() {
boolean componentSelected = getSelectedComponent() != null;
selectSeparationButton.setEnabled(componentSelected);

View File

@ -0,0 +1,122 @@
package net.sf.openrocket.gui.rocketfigure;
import net.sf.openrocket.util.Coordinate;
import net.sf.openrocket.util.Transformation;
import java.awt.Shape;
import java.awt.geom.Line2D;
import java.awt.geom.Rectangle2D;
/**
* Shapes of an "empty"/virtual object, e.g. a podset without any children.
* The shape is a center square with additional lines on the north, east, south and west side of the square.
*
* @author Sibo Van Gool <sibo.vangool@hotmail.com>
*/
public class EmptyShapes extends RocketComponentShape {
/**
* Returns the empty shape in the side view.
* @param radius radius of the center square
*/
public static Shape[] getShapesSide(final Transformation transformation, final double radius) {
final Coordinate instanceAbsoluteLocation = transformation.transform(Coordinate.ZERO);
double x = instanceAbsoluteLocation.x;
double y = instanceAbsoluteLocation.y;
double lineLength = getLineLength(radius); // Length of the line protruding the center square
final Shape[] s = new Shape[5];
// Center square
s[0] = new Rectangle2D.Double(x - radius, y - radius, 2 * radius, 2 * radius);
// Line North
s[1] = new Line2D.Double(x, y + radius, x, y + radius + lineLength);
// Line East
s[2] = new Line2D.Double(x + radius, y, x + radius + lineLength, y);
// Line South
s[3] = new Line2D.Double(x, y - radius, x, y - radius - lineLength);
// Line West
s[4] = new Line2D.Double(x - radius, y, x - radius - lineLength, y);
return s;
}
/**
* Returns the empty shape in the side view, with an additional square encompassing the shape that can be used
* for selecting the object.
* @param radius radius of the center square
*/
public static Shape[] getShapesSideWithSelectionSquare(final Transformation transformation, final double radius) {
final Coordinate instanceAbsoluteLocation = transformation.transform(Coordinate.ZERO);
double x = instanceAbsoluteLocation.x;
double y = instanceAbsoluteLocation.y;
double lineLength = getLineLength(radius); // Length of the line protruding the center square
Shape[] shapes = getShapesSide(transformation, radius);
// Invisible shape for selecting the component (= a square encompassing the component)
Shape selectionShape = new Rectangle2D.Double(x - radius - lineLength, y - radius - lineLength,
lineLength * 2 + radius * 2, lineLength * 2 + radius * 2);
Shape[] finalShapes = new Shape[shapes.length + 1];
System.arraycopy(shapes, 0, finalShapes, 0, shapes.length);
finalShapes[finalShapes.length - 1] = selectionShape;
return finalShapes;
}
/**
* Returns the empty shape in the side view.
* @param radius radius of the center square
*/
public static Shape[] getShapesBack(final Transformation transformation, final double radius) {
final Coordinate instanceAbsoluteLocation = transformation.transform(Coordinate.ZERO);
double z = instanceAbsoluteLocation.z;
double y = instanceAbsoluteLocation.y;
double lineLength = getLineLength(radius); // Length of the line protruding the center square
final Shape[] s = new Shape[5];
// Center square
s[0] = new Rectangle2D.Double(z - radius, y - radius, 2 * radius, 2 * radius);
// Line North
s[1] = new Line2D.Double(z, y + radius, z, y + radius + lineLength);
// Line East
s[2] = new Line2D.Double(z + radius, y, z + radius + lineLength, y);
// Line South
s[3] = new Line2D.Double(z, y - radius, z, y - radius - lineLength);
// Line West
s[4] = new Line2D.Double(z - radius, y, z - radius - lineLength, y);
return s;
}
/**
* Returns the empty shape in the back view, with an additional square encompassing the shape that can be used
* for selecting the object.
* @param radius radius of the center square
*/
public static Shape[] getShapesBackWithSelectionSquare(final Transformation transformation, final double radius) {
final Coordinate instanceAbsoluteLocation = transformation.transform(Coordinate.ZERO);
double z = instanceAbsoluteLocation.z;
double y = instanceAbsoluteLocation.y;
double lineLength = getLineLength(radius); // Length of the line protruding the center square
Shape[] shapes = getShapesBack(transformation, radius);
// Invisible shape for selecting the component (= a square encompassing the component)
Shape selectionShape = new Rectangle2D.Double(z - radius - lineLength, y - radius - lineLength,
lineLength * 2 + radius * 2, lineLength * 2 + radius * 2);
Shape[] finalShapes = new Shape[shapes.length + 1];
System.arraycopy(shapes, 0, finalShapes, 0, shapes.length);
finalShapes[finalShapes.length - 1] = selectionShape;
return finalShapes;
}
private static double getLineLength(double radius) {
return radius * 3;
}
}

View File

@ -0,0 +1,48 @@
package net.sf.openrocket.gui.rocketfigure;
import net.sf.openrocket.rocketcomponent.ParallelStage;
import net.sf.openrocket.rocketcomponent.RocketComponent;
import net.sf.openrocket.util.Color;
import net.sf.openrocket.util.Transformation;
import java.awt.Shape;
public class ParallelStageShapes extends RocketComponentShape {
public static final Color boosterColor = new Color(198,163,184);
public static RocketComponentShape[] getShapesSide(final RocketComponent component, final Transformation transformation) {
ParallelStage booster = (ParallelStage)component;
double radius = getDisplayRadius(booster);
Shape[] s = EmptyShapes.getShapesSideWithSelectionSquare(transformation, radius);
RocketComponentShape[] shapes = RocketComponentShape.toArray(s, component);
// Set the color of the shapes
for (int i = 0; i < shapes.length - 1; i++) {
shapes[i].setColor(boosterColor);
}
shapes[shapes.length - 1].setColor(Color.INVISIBLE);
return shapes;
}
public static RocketComponentShape[] getShapesBack(final RocketComponent component, final Transformation transformation) {
ParallelStage booster = (ParallelStage)component;
double radius = getDisplayRadius(booster);
Shape[] s = EmptyShapes.getShapesBackWithSelectionSquare(transformation, radius);
RocketComponentShape[] shapes = RocketComponentShape.toArray(s, component);
// Set the color of the shapes
for (int i = 0; i < shapes.length - 1; i++) {
shapes[i].setColor(boosterColor);
}
shapes[shapes.length - 1].setColor(Color.INVISIBLE);
return shapes;
}
private static double getDisplayRadius(ParallelStage booster) {
return booster.getRocket().getBoundingRadius() * 0.03;
}
}

View File

@ -0,0 +1,48 @@
package net.sf.openrocket.gui.rocketfigure;
import net.sf.openrocket.rocketcomponent.PodSet;
import net.sf.openrocket.rocketcomponent.RocketComponent;
import net.sf.openrocket.util.Color;
import net.sf.openrocket.util.Transformation;
import java.awt.Shape;
public class PodSetShapes extends RocketComponentShape {
public static final Color podsetColor = new Color(160,160,215);
public static RocketComponentShape[] getShapesSide(final RocketComponent component, final Transformation transformation) {
PodSet podset = (PodSet)component;
double radius = getDisplayRadius(podset);
Shape[] s = EmptyShapes.getShapesSideWithSelectionSquare(transformation, radius);
RocketComponentShape[] shapes = RocketComponentShape.toArray(s, component);
// Set the color of the shapes
for (int i = 0; i < shapes.length - 1; i++) {
shapes[i].setColor(podsetColor);
}
shapes[shapes.length - 1].setColor(Color.INVISIBLE);
return shapes;
}
public static RocketComponentShape[] getShapesBack(final RocketComponent component, final Transformation transformation) {
PodSet podset = (PodSet)component;
double radius = getDisplayRadius(podset);
Shape[] s = EmptyShapes.getShapesBackWithSelectionSquare(transformation, radius);
RocketComponentShape[] shapes = RocketComponentShape.toArray(s, component);
// Set the color of the shapes
for (int i = 0; i < shapes.length - 1; i++) {
shapes[i].setColor(podsetColor);
}
shapes[shapes.length - 1].setColor(Color.INVISIBLE);
return shapes;
}
private static double getDisplayRadius(PodSet podset) {
return podset.getRocket().getBoundingRadius() * 0.03;
}
}

View File

@ -64,6 +64,10 @@ public class RocketComponentShape {
return new RocketComponentShape[0];
}
public Color getColor() {
return color;
}
public void setColor(Color color) {
this.color = color;
}

View File

@ -17,6 +17,9 @@ import java.awt.geom.Rectangle2D;
import java.util.*;
import java.util.Map.Entry;
import net.sf.openrocket.rocketcomponent.AxialStage;
import net.sf.openrocket.rocketcomponent.ParallelStage;
import net.sf.openrocket.rocketcomponent.PodSet;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@ -26,7 +29,6 @@ import net.sf.openrocket.gui.util.ColorConversion;
import net.sf.openrocket.gui.util.SwingPreferences;
import net.sf.openrocket.motor.Motor;
import net.sf.openrocket.motor.MotorConfiguration;
import net.sf.openrocket.rocketcomponent.ComponentAssembly;
import net.sf.openrocket.rocketcomponent.FlightConfiguration;
import net.sf.openrocket.rocketcomponent.InstanceContext;
import net.sf.openrocket.rocketcomponent.MotorMount;
@ -52,6 +54,7 @@ import net.sf.openrocket.util.Transformation;
public class RocketFigure extends AbstractScaleFigure {
private final static Logger log = LoggerFactory.getLogger(FinPointFigure.class);
protected final SwingPreferences preferences = (SwingPreferences) Application.getPreferences();
private static final String ROCKET_FIGURE_PACKAGE = "net.sf.openrocket.gui.rocketfigure";
private static final String ROCKET_FIGURE_SUFFIX = "Shapes";
@ -378,6 +381,20 @@ public class RocketFigure extends AbstractScaleFigure {
for(Entry<RocketComponent, ArrayList<InstanceContext>> entry: config.getActiveInstances().entrySet() ) {
final RocketComponent comp = entry.getKey();
// Only draw podsets when they are selected
if ((comp instanceof PodSet || comp instanceof ParallelStage) && preferences.isShowMarkers()) {
boolean selected = false;
// Check if component is in the selection
for (RocketComponent component : selection) {
if (comp == component) {
selected = true;
break;
}
}
if (!selected) continue;
}
final ArrayList<InstanceContext> contextList = entry.getValue();
@ -390,8 +407,12 @@ public class RocketFigure extends AbstractScaleFigure {
/**
* Gets the shapes required to draw the component.
*
* @param component
*
* @param allShapes output buffer for the shapes to add to
* @param viewType the view type to draw the component in
* @param component component to draw and add to <allShapes>
* @param transformation transformation to apply to the component before drawing it
* @param color color to draw the component in
*
* @return the <code>ArrayList</code> containing all the shapes to draw.
*/
@ -399,10 +420,11 @@ public class RocketFigure extends AbstractScaleFigure {
PriorityQueue<RocketComponentShape> allShapes, // this is the output parameter
final RocketPanel.VIEW_TYPE viewType,
final RocketComponent component,
final Transformation transformation) {
final Transformation transformation,
final net.sf.openrocket.util.Color color) {
Reflection.Method m;
if(( component instanceof Rocket)||( component instanceof ComponentAssembly )){
if ((component instanceof Rocket) || (component instanceof AxialStage && !(component instanceof ParallelStage))){
// no-op; no shapes here
return allShapes;
}
@ -431,9 +453,35 @@ public class RocketFigure extends AbstractScaleFigure {
RocketComponentShape[] returnValue = (RocketComponentShape[]) m.invokeStatic(component, transformation);
if (color != null) {
for (RocketComponentShape rcs : returnValue) {
if (rcs.getColor() == net.sf.openrocket.util.Color.INVISIBLE) continue; // don't change the color of invisible (often selection) components
rcs.setColor(color);
}
}
allShapes.addAll(Arrays.asList(returnValue));
return allShapes;
}
/**
* Gets the shapes required to draw the component.
*
* @param allShapes output buffer for the shapes to add to
* @param viewType the view type to draw the component in
* @param component component to draw and add to <allShapes>
* @param transformation transformation to apply to the component before drawing it
*
* @return the <code>ArrayList</code> containing all the shapes to draw.
*/
private static PriorityQueue<RocketComponentShape> addThisShape(
PriorityQueue<RocketComponentShape> allShapes, // this is the output parameter
final RocketPanel.VIEW_TYPE viewType,
final RocketComponent component,
final Transformation transformation) {
return addThisShape(allShapes, viewType, component, transformation, null);
}
/**

View File

@ -252,7 +252,7 @@ public class RocketPanel extends JPanel implements TreeSelectionListener, Change
});
}
private void updateFigures() {
public void updateFigures() {
if (!is3d)
figure.updateFigure();
else

View File

@ -151,7 +151,7 @@ public class SimulationEditDialog extends JDialog {
final Rocket rkt = document.getRocket();
final FlightConfiguration config = rkt.getFlightConfiguration(simulationList[0].getFlightConfigurationId());
final ConfigurationComboBox configComboBox = new ConfigurationComboBox(rkt);
final ConfigurationComboBox configComboBox = new ConfigurationComboBox(rkt, false);
configComboBox.setSelectedItem(config);
//// Select the motor configuration to use.

View File

@ -0,0 +1,74 @@
package net.sf.openrocket.gui.util;
import java.awt.GraphicsDevice;
import java.awt.Window;
/**
* Helper class for setting the location of a Swing window. E.g. to check when the window is outside the screen and
* recenter it if so.
*
* @author Sibo Van Gool <sibo.vangool@hotmail.com>
*/
public abstract class WindowLocationUtil {
/**
* Sets the location of the window, but don't go outside the screen.
* @param window the window to move
* @param x the target x position on the screen
* @param y the target y position on the screen
*/
public static void setLocationWithinScreen(Window window, int x, int y) {
java.awt.Dimension screenSize = java.awt.Toolkit.getDefaultToolkit().getScreenSize();
java.awt.Dimension windowSize = window.getSize();
int screenWidth = screenSize.width;
int screenHeight = screenSize.height;
int windowWidth = windowSize.width;
int windowHeight = windowSize.height;
int xPos = x;
int yPos = y;
if (xPos + windowWidth > screenWidth) {
xPos = screenWidth - windowWidth;
}
if (yPos + windowHeight > screenHeight) {
yPos = screenHeight - windowHeight;
}
window.setLocation(xPos, yPos);
}
/**
* Moves the window to the center of the screen if its location is outside the boundary of the screen.
* @param window window to move
*/
public static void moveIfOutsideOfMonitor(Window window) {
GraphicsDevice currentDevice = window.getGraphicsConfiguration().getDevice();
if (currentDevice != null && window.isVisible() &&
!currentDevice.getDefaultConfiguration().getBounds().contains(window.getLocationOnScreen())) {
int width = currentDevice.getDefaultConfiguration().getBounds().width;
int height = currentDevice.getDefaultConfiguration().getBounds().height;
window.setLocation(
((width / 2) - (window.getSize().width / 2)) + currentDevice.getDefaultConfiguration().getBounds().x,
((height / 2) - (window.getSize().height / 2)) + currentDevice.getDefaultConfiguration().getBounds().y
);
}
}
/**
* Moves the window to the center of the screen if it is on another monitor as the parent window, or if its location
* is outside the boundary of the parent's monitor screen.
* @param window window to move
* @param parent parent window
*/
public static void moveIfOutsideOfParentMonitor(Window window, Window parent) {
GraphicsDevice parentDevice = parent.getGraphicsConfiguration().getDevice();
GraphicsDevice currentDevice = window.getGraphicsConfiguration().getDevice();
if (parentDevice != null && (currentDevice == null || currentDevice != parentDevice ||
(window.isVisible() && !parentDevice.getDefaultConfiguration().getBounds().contains(
window.getLocationOnScreen())))) {
int width = parentDevice.getDefaultConfiguration().getBounds().width;
int height = parentDevice.getDefaultConfiguration().getBounds().height;
window.setLocation(
((width / 2) - (window.getSize().width / 2)) + parentDevice.getDefaultConfiguration().getBounds().x,
((height / 2) - (window.getSize().height / 2)) + parentDevice.getDefaultConfiguration().getBounds().y
);
}
}
}

View File

@ -223,7 +223,8 @@ public class SwingStartup {
// Starting action (load files or open new document)
log.info("Opening main application window");
if (!handleCommandLine(args)) {
BasicFrame.reopen();
BasicFrame startupFrame = BasicFrame.reopen();
BasicFrame.setStartupFrame(startupFrame);
}
// Check whether update info has been fetched or whether it needs more time
@ -298,7 +299,7 @@ public class SwingStartup {
// Check command-line for files
boolean opened = false;
for (String file : args) {
if (BasicFrame.open(new File(file), null)) {
if (BasicFrame.open(new File(file), null) != null) {
opened = true;
}
}

View File

@ -71,7 +71,7 @@ public class IntegrationTest {
private Action undoAction, redoAction;
private AerodynamicCalculator aeroCalc = new BarrowmanCalculator();
private FlightConfiguration config;
private FlightConfigurationId fcid;
private FlightConditions conditions;
private String massComponentID = null;
@ -112,14 +112,12 @@ public class IntegrationTest {
undoAction = UndoRedoAction.newUndoAction(document);
redoAction = UndoRedoAction.newRedoAction(document);
FlightConfigurationId fcid = document.getSimulation(0).getFlightConfigurationId();
config = document.getRocket().getFlightConfiguration(fcid);
fcid = document.getSimulation(0).getFlightConfigurationId();
FlightConfiguration config = document.getRocket().getFlightConfiguration(fcid);
conditions = new FlightConditions(config);
// Test undo state
checkUndoState(null, null);
InnerTube mmt = (InnerTube)config.getRocket().getChild(0).getChild(1).getChild(2);
// Compute cg+cp + altitude
// double cgx, double mass, double cpx, double cna)
@ -330,6 +328,7 @@ public class IntegrationTest {
}
private void checkCgCp(double cgx, double mass, double cpx, double cna) {
FlightConfiguration config = document.getRocket().getFlightConfiguration(fcid);
final RigidBody launchData = MassCalculator.calculateLaunch(config);
final Coordinate cg = launchData.getCenterOfMass();
assertEquals(cgx, cg.x, 0.001);