Merge branch 'unstable' into issue-1894
1
.github/FUNDING.yml
vendored
Normal file
@ -0,0 +1 @@
|
||||
open_collective: openrocket
|
||||
@ -17,7 +17,7 @@
|
||||
<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/javax.activation-api.2.3.1.jar"/>
|
||||
<classpathentry kind="lib" path="lib/javax.activation-api-2.3.1.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"/>
|
||||
@ -36,5 +36,8 @@
|
||||
<classpathentry kind="lib" path="lib/jaxb-api.2.3.1.jar"/>
|
||||
<classpathentry kind="lib" path="lib/jaxb-runtime.2.3.1.jar"/>
|
||||
<classpathentry kind="lib" path="lib/guava-26.0-jre.jar"/>
|
||||
<classpathentry kind="lib" path="lib/istack-commons-runtime.jar"/>
|
||||
<classpathentry kind="lib" path="lib/graal-sdk-22.1.0.1.jar"/>
|
||||
<classpathentry kind="lib" path="lib/js-scriptengine-22.1.0.1.jar"/>
|
||||
<classpathentry kind="output" path="bin"/>
|
||||
</classpath>
|
||||
|
||||
|
Before Width: | Height: | Size: 225 B |
|
Before Width: | Height: | Size: 473 B |
|
Before Width: | Height: | Size: 624 B After Width: | Height: | Size: 649 B |
|
Before Width: | Height: | Size: 395 B |
|
Before Width: | Height: | Size: 1.3 KiB |
|
Before Width: | Height: | Size: 2.0 KiB After Width: | Height: | Size: 2.6 KiB |
|
Before Width: | Height: | Size: 537 B |
|
Before Width: | Height: | Size: 1.7 KiB |
|
Before Width: | Height: | Size: 3.8 KiB After Width: | Height: | Size: 4.3 KiB |
|
Before Width: | Height: | Size: 647 B |
|
Before Width: | Height: | Size: 2.1 KiB |
|
Before Width: | Height: | Size: 5.8 KiB After Width: | Height: | Size: 6.3 KiB |
BIN
core/resources-src/pix/icon/icon-128.png
Normal file
|
After Width: | Height: | Size: 18 KiB |
|
Before Width: | Height: | Size: 96 KiB |
|
Before Width: | Height: | Size: 63 KiB After Width: | Height: | Size: 53 KiB |
BIN
core/resources-src/pix/icon/icon-256.xcf
Normal file
363
core/resources-src/pix/icon/icon-design.ai
Normal file
BIN
core/resources-src/pix/icon/logo_rocket.ork
Normal file
BIN
core/resources-src/pix/splashscreen-2.1.png
Normal file
|
After Width: | Height: | Size: 136 KiB |
BIN
core/resources-src/pix/splashscreen-2.1.xcf
Normal file
@ -50,6 +50,7 @@ RocketActions.MoveDownAct.ttip.Movedown = Move this component downwards.
|
||||
|
||||
! RocketPanel
|
||||
RocketPanel.FigTypeAct.SideView = Side view
|
||||
RocketPanel.FigTypeAct.TopView = Top view
|
||||
RocketPanel.FigTypeAct.BackView = Back view
|
||||
RocketPanel.FigTypeAct.Figure3D = 3D Figure
|
||||
RocketPanel.FigTypeAct.Finished = 3D Finished
|
||||
@ -562,6 +563,7 @@ SimuRunDlg.msg.Unabletosim = Unable to simulate:
|
||||
SimuRunDlg.msg.errorOccurred = An error occurred during the simulation:
|
||||
|
||||
BasicEventSimulationEngine.error.noMotorsDefined = No motors defined in the simulation.
|
||||
BasicEventSimulationEngine.error.cantCalculateStability = Can't calculate rocket stability.
|
||||
BasicEventSimulationEngine.error.earlyMotorBurnout = Motor burnout without liftoff.
|
||||
BasicEventSimulationEngine.error.noConfiguredIgnition = No motors configured to ignite at liftoff
|
||||
BasicEventSimulationEngine.error.noIgnition = No motors ignited.
|
||||
@ -718,6 +720,11 @@ simplotpanel.RIGHT_NAME = Right
|
||||
simplotpanel.CUSTOM = Custom
|
||||
SimulationPlotPanel.error.noPlotSelected = Please add one or more variables to plot on the Y-axis.
|
||||
SimulationPlotPanel.error.noPlotSelected.title = Nothing to plot
|
||||
simplotpanel.MarkerStyle.lbl.MarkerStyle = Marker style:
|
||||
simplotpanel.MarkerStyle.lbl.MarkerStyle.ttip = Style of the flight event marker (how it's drawn in the simulation plot)
|
||||
simplotpanel.MarkerStyle.btn.VerticalMarker = Vertical line
|
||||
simplotpanel.MarkerStyle.btn.Icon = Icon
|
||||
simplotpanel.MarkerStyle.OnlyInTime = Only available for time domain, other domains only support icon markers
|
||||
|
||||
! Component add buttons
|
||||
compaddbuttons.AxialStage = Stage
|
||||
@ -819,7 +826,6 @@ ringcompcfg.Radialdirection = Radial direction:
|
||||
ringcompcfg.radialdirectionfrom = The radial direction from the rocket centerline
|
||||
ringcompcfg.but.Reset = Reset
|
||||
ringcompcfg.but.Resetcomponant = Resets the component to the rocket centerline.
|
||||
ringcompcfg.EngineBlock.desc = <html>An <b>engine block</b> stops the motor from moving forwards in the motor mount tube.<br><br>In order to add a motor, create a <b>body tube</b> or <b>inner tube</b> and mark it as a motor mount in the <em>Motor</em> tab.
|
||||
ringcompcfg.note.desc = Note: An inner tube will not affect the aerodynamics of the rocket even if it is located outside of the body tube.
|
||||
|
||||
|
||||
@ -972,6 +978,37 @@ RocketCompCfg.tab.Outside = Outside
|
||||
RocketCompCfg.tab.Inside = Inside
|
||||
RocketCompCfg.tab.RightSide = Right Side
|
||||
RocketCompCfg.tab.LeftSide = Left Side
|
||||
RocketCompCfg.btn.OK.ttip = Keep changes and close the dialog
|
||||
RocketCompCfg.btn.Cancel.ttip = Discard changes and close the dialog
|
||||
RocketCompCfg.CancelOperation.msg.discardChanges = <html>Are you sure you want to <b>discard</b> your <b>changes</b> to this component?</html>
|
||||
RocketCompCfg.CancelOperation.msg.undoAdd = <html>Are you sure you want to <b>undo adding</b> this component?</html>
|
||||
RocketCompCfg.CancelOperation.title = Cancel operation
|
||||
RocketCompCfg.CancelOperation.checkbox.dontAskAgain = Don't ask me again
|
||||
RocketCompCfg.btn.ComponentInfo.ttip = Show/hide informative text about this component.
|
||||
|
||||
! ComponentInfo
|
||||
ComponentInfo.Rocket = This is your rocket. Nothing more to say about it. Have fun designing and building it! :)
|
||||
ComponentInfo.AxialStage = A <b>stage</b> is a <b>section</b> of the model rocket that contains <b>motors</b> which ignite successively and <b>separate</b> after motor burnout.<br>Each stage must safely descend after separation. The main stage, often called the <b>'Sustainer'</b>, usually descends with a <b>recovery device</b>.
|
||||
ComponentInfo.ParallelStage = A <b>booster</b> is a fictional component that acts as an <b>attachment</b> point to a <b>body tube</b> and can <b>separate</b> from that body tube at a specified time during flight.<br>The most common use of a booster is the attachment of a <b>strap-on booster</b>.
|
||||
ComponentInfo.PodSet = A <b>pod</b> is a fictional component that acts as an <b>attachment</b> point to a <b>body tube</b>.<br>Once defined, other components can be attached to the pod to create complex rocket geometries.
|
||||
ComponentInfo.NoseCone = A <b>nose cone</b> is the <b>front end</b> of the rocket airframe. Nose cones vary widely in shape.<br>The back end can be cut down to form an <b>internal shoulder</b> that slides inside of a body tube to hold the nose cone in place.
|
||||
ComponentInfo.BodyTube = A <b>body tube</b> is primarily used for the <b>structure</b> of the exterior body of the model rocket.
|
||||
ComponentInfo.Transition = A <b>transition</b> is the part of the airframe that <b>connects</b> two <b>body tubes</b> having <b>different</b> outside <b>diameters</b>.<br>Both ends of a transition are cut down to form an internal shoulder that slides inside of each body tube to hold the transition in place at both ends.
|
||||
ComponentInfo.TrapezoidFinSet = Fins help <b>stabilize</b> the rocket. The most common fin shape is <b>trapezoidal</b>, four sides with parallel root and tip chords (the edge that glues to the body tube and the outer edge).
|
||||
ComponentInfo.EllipticalFinSet = Fins help <b>stabilize</b> the rocket. The most efficient fin shape is <b>elliptical</b>. This shape induces the <b>least amount of drag</b> of any fin shape. It is commonly used for competition flying events.
|
||||
ComponentInfo.FreeformFinSet = Fins help <b>stabilize</b> the rocket. The most versatile fin component is the <b>freeform fin</b>. This fin component allows the creation of virtually any solid fin shape, with the ability to manually enter data points or import a shape from an image file.
|
||||
ComponentInfo.TubeFinSet = <b>Tube fins</b> are used to keep the model rocket going <b>straight after launch</b>. Tube fins vary in length and diameter, and may have either straight or curved ends.<br>Currently, OpenRocket only supports straight-perpendicular cut ends.
|
||||
ComponentInfo.RailButton = <b>Rail buttons</b> keep the model rocket from <b>changing orientation</b> when it launches. Rail buttons are most commonly used on larger model rockets, in pairs, <b>instead</b> of <b>launch lugs</b>.<br>They can be mounted to the outside of the body tube with a screw and internal nut.<br>A rail button looks like two washers with a spacer in between; one washer is against the body tube and the other slides inside the launch rail.
|
||||
ComponentInfo.LaunchLug = A <b>launch lug</b> is the most common guide used to keep smaller model rockets from <b>changing orientation</b> until the rocket leaves the end of the launch rod.
|
||||
ComponentInfo.InnerTube = <b>Inner tubes</b> are most commonly used for <b>motor tubes</b>, but may also be part of other internal systems, such as an ejection baffles and adjustable weight designs.<br>Inner tubes may be positioned radially inside of a body tube and, when used as a motor tube, may be clustered.
|
||||
ComponentInfo.TubeCoupler = A <b>coupler</b> is a short tube that <b>connects</b> two <b>tubes</b> with the <b>same diameters</b>.<br>In model rockets that use electronics, a coupler may be used for the <b>avionics bay</b>.<br>The tubes are often glued to the coupler to stop them from sliding.
|
||||
ComponentInfo.CenteringRing = <b>Centering rings</b> are used to <b>position</b> one or more <b>inner tubes</b> inside of a <b>body tube</b>.<br>Fin sets have an <b>automatic fin tab</b> feature for determining an ideal fin tab configuration based on an inner tube positioned below the root chord of the fins. This also requires two centering below the root chord.
|
||||
ComponentInfo.Bulkhead = A <b>bulkhead</b> is a disk that may or may not have a small hole in the center. Bulkheads are used to <b>seal</b> one area of a model rocket from another or to mount recovery system eyes for <b>shock cord attachment</b>, such as nose cone caps and avionics bay lids.
|
||||
ComponentInfo.EngineBlock = An <b>engine block stops</b> the <b>motor</b> from <b>moving forward</b> in the motor mount tube.<br>In order to add a motor, create a <b>body tube</b> or <b>inner tube</b> and mark it as a motor mount in the <em>Motor</em> tab.
|
||||
ComponentInfo.Parachute = The <b>parachute</b> is the most common <b>recovery device</b>. Smal model rocket parachutes are made of thin, light-weight materials, such as polyethylene or Mylar, while larger parachutes are most commonly made of rip-stop nylon. Parachutes may be decorated in bright and contrasting colors/patterns to improve visibility.<br><b>Shroud lines</b> attach the parachute <b>canopy</b> to the <b>shock cord</b>. The shroud lines are sometimes brought together and attached using a swivel.
|
||||
ComponentInfo.Streamer = A <b>streamer</b> is a <b>recovery device</b> that, when ejected, unrolls and <b>slows</b> the model <b>rocket</b> during descent.<br>A streamer is a long, narrow, <b>rectangular strip</b> of crepe paper or thin plastic film. The width and length of the streamer are adjusted to match the weight of the rocket, but a <b>10 to 1 length to width ratio</b> is considered the best for a streamer.
|
||||
ComponentInfo.ShockCord = A <b>shock cord</b> attaches the <b>nose cone</b> and <b>recovery device</b> to the <b>body tube</b>, keeping the model rocket together during <b>descent</b>.<br>Smaller rockets commonly have short elastic shock cords, while larger rockets have long shock cords made from materials such as Nylon or heat resistant Kevlar webbing.
|
||||
ComponentInfo.MassComponent = A <b>mass component</b> may be used to simulate a <b>component</b> that is <b>not otherwise listed</b>.<br>In OpenRocket, this component type may be designated for instance as an <b>altimeter</b>, a <b>flight computer</b>, a <b>battery</b>\u2026 Each designation has its own unique icon to ease identification.
|
||||
|
||||
! BulkheadConfig
|
||||
BulkheadCfg.tab.Diameter = Diameter:
|
||||
@ -1148,6 +1185,8 @@ NoseConeCfg.tab.General = General
|
||||
NoseConeCfg.tab.ttip.General = General properties
|
||||
NoseConeCfg.tab.Shoulder = Shoulder
|
||||
NoseConeCfg.tab.ttip.Shoulder = Shoulder properties
|
||||
NoseConeCfg.checkbox.Flip = Flip to tail cone
|
||||
NoseConeCfg.checkbox.Flip.ttip = Flips the nose cone direction to a tail cone.
|
||||
|
||||
! ParachuteConfig
|
||||
Parachute.Parachute = Parachute
|
||||
@ -1847,6 +1886,7 @@ PlotConfiguration.Groundtrack = Ground track
|
||||
Warning.LargeAOA.str1 = Large angle of attack encountered.
|
||||
Warning.LargeAOA.str2 = Large angle of attack encountered (
|
||||
Warning.DISCONTINUITY = Discontinuity in rocket body diameter
|
||||
Warning.OPEN_AIRFRAME_FORWARD = Forward end of airframe is open (radius is > 0)
|
||||
Warning.THICK_FIN = Thick fins may not simulate accurately.
|
||||
Warning.JAGGED_EDGED_FIN = Jagged-edged fin predictions may be inaccurate.
|
||||
Warning.LISTENERS_AFFECTED = Listeners modified the flight simulation
|
||||
@ -2150,7 +2190,9 @@ ExportDecalDialog.source.exception = Could not find decal source file ''{0}''.<b
|
||||
ComponentPresetChooserDialog.title = Choose component preset
|
||||
ComponentPresetChooserDialog.filter.label = Filter by text:
|
||||
ComponentPresetChooserDialog.checkbox.filterAftDiameter = Match aft diameter
|
||||
ComponentPresetChooserDialog.checkbox.filterAftDiameter.ttip = Search for components with the same aft diameter as the next component
|
||||
ComponentPresetChooserDialog.checkbox.filterForeDiameter = Match fore diameter
|
||||
ComponentPresetChooserDialog.checkbox.filterForeDiameter.ttip = Search for components with the same fore diameter as the previous component
|
||||
ComponentPresetChooserDialog.menu.sortAsc = Sort Ascending
|
||||
ComponentPresetChooserDialog.menu.sortDesc = Sort Descending
|
||||
ComponentPresetChooserDialog.menu.units = Units
|
||||
|
||||
@ -817,7 +817,6 @@ ringcompcfg.Radialdirection = :الإتجاه الشعاعي
|
||||
ringcompcfg.radialdirectionfrom = :الإتجاه الشعاعي من خط الوسط للصاروخ
|
||||
ringcompcfg.but.Reset = إعادة ضبط
|
||||
ringcompcfg.but.Resetcomponant = .يعيد تعيين المكون إلى خط الوسط للصاروخ
|
||||
ringcompcfg.EngineBlock.desc = <html>.كتلة المحرك تمنعه من التحرك للأمام في أنبوب الحامل للمحرك<br><br>.من أجل إضافة محرك ، قم بإنشاء أنبوب جسم أو أنبوب داخلي وقم بتمييزه على أنه حامل محرك في علامة تبويب المحرك
|
||||
ringcompcfg.note.desc = .ملاحظة: الأنبوب الداخلي لن يؤثر على الديناميكا الهوائية للصاروخ حتى لو كان موجودًا خارج أنبوب الجسم
|
||||
|
||||
|
||||
@ -971,6 +970,9 @@ RocketCompCfg.tab.Inside = من الداخل
|
||||
RocketCompCfg.tab.RightSide = الجانب اليميني
|
||||
RocketCompCfg.tab.LeftSide = الجانب اليساري
|
||||
|
||||
! ComponentInfo
|
||||
ComponentInfo.EngineBlock = .كتلة المحرك تمنعه من التحرك للأمام في أنبوب الحامل للمحرك<br><br>.من أجل إضافة محرك ، قم بإنشاء أنبوب جسم أو أنبوب داخلي وقم بتمييزه على أنه حامل محرك في علامة تبويب المحرك
|
||||
|
||||
! BulkheadConfig
|
||||
BulkheadCfg.tab.Diameter = :القطر
|
||||
BulkheadCfg.tab.Thickness = :السماكة
|
||||
|
||||
@ -568,7 +568,6 @@ ringcompcfg.Radialdirection = Radi
|
||||
ringcompcfg.radialdirectionfrom = Radiální vzdálenost od smeru osy
|
||||
ringcompcfg.but.Reset = Reset
|
||||
ringcompcfg.but.Resetcomponant = Resetuj komponentu od osy rakety
|
||||
ringcompcfg.EngineBlock.desc = <html>An <b>blok motoru</b> zastaví motor v pohybu vzad v motorové trubici.<br><br>Pokud se pridá motor vytvorí <b>telo</b> nebo <b>skrytou trubku tube</b> a oznací ji jako montá\u017E motoru v<em>Motoru</em> tab.
|
||||
ringcompcfg.note.desc = Poznámka: Vnitrní trubka nemá effekt na aerodynamiku motoru i kdy\u017E je umístena mimo telo rakety.
|
||||
|
||||
|
||||
@ -662,6 +661,9 @@ RocketCompCfg.title.Aftshoulder = Dr\u017E
|
||||
RocketCompCfg.border.Foreshoulder = Dr\u017Eák prídi
|
||||
!RocketCompCfg.lbl.Length = Délka:
|
||||
|
||||
! ComponentInfo
|
||||
ComponentInfo.EngineBlock = An <b>blok motoru</b> zastaví motor v pohybu vzad v motorové trubici.<br><br>Pokud se pridá motor vytvorí <b>telo</b> nebo <b>skrytou trubku tube</b> a oznací ji jako montá\u017E motoru v<em>Motoru</em> tab.
|
||||
|
||||
! BulkheadConfig
|
||||
BulkheadCfg.tab.Diameter = Prumer:
|
||||
BulkheadCfg.tab.Thickness = Tlou\u0161tka:
|
||||
|
||||
@ -625,7 +625,6 @@ ringcompcfg.Radialdirection = Radiale Richtung
|
||||
ringcompcfg.radialdirectionfrom = Die radiale Richtung von der Raketenmittellinie
|
||||
ringcompcfg.but.Reset = Zurücksetzen
|
||||
ringcompcfg.but.Resetcomponant = Komponente auf die Raketenmittellinie zurücksetzen
|
||||
ringcompcfg.EngineBlock.desc = <html>Eine <b>Motorhalterung</b> verhindert, dass der Motor sich im Rohr nach vorne bewegt.<br><br>Um einen Motor hinzuzufügen, ein <b>Körperrohr</b> oder ein <b>Innenrohr</b> hinzufügen und im Reiter <em>Motor</em> als Motorhalterung markieren.
|
||||
ringcompcfg.note.desc = Hinweis: Innenrohre beeinflussen die Aerodynamik der Rakete nicht, auch wenn sie außerhalb des Körperohres liegen.
|
||||
|
||||
|
||||
@ -719,6 +718,9 @@ RocketCompCfg.title.Aftshoulder = Schulter hinten
|
||||
RocketCompCfg.border.Foreshoulder = Schulter vorn
|
||||
!RocketCompCfg.lbl.Length = Length:
|
||||
|
||||
! ComponentInfo
|
||||
ComponentInfo.EngineBlock = Eine <b>Motorhalterung</b> verhindert, dass der Motor sich im Rohr nach vorne bewegt.<br><br>Um einen Motor hinzuzufügen, ein <b>Körperrohr</b> oder ein <b>Innenrohr</b> hinzufügen und im Reiter <em>Motor</em> als Motorhalterung markieren.
|
||||
|
||||
! BulkheadConfig
|
||||
BulkheadCfg.tab.Radius = Radius:
|
||||
BulkheadCfg.tab.Thickness = Wandstärke:
|
||||
|
||||
@ -869,6 +869,9 @@ RocketCompCfg.title.Noseconeshoulder = Acople de la ojiva
|
||||
RocketCompCfg.ttip.Endcapped = Si el extremo del soporte est\u00e1 truncado.
|
||||
RocketCompCfg.lbl.Componentname.ttip = El nombre del componente.
|
||||
|
||||
! ComponentInfo
|
||||
ComponentInfo.EngineBlock = Un <b>ret\u00e9n de motor</b> impide que el motor se desplace hacia delante, por dentro del tubo porta motor.<br><br>Para a\u00f1adir un motor, cree un <b>Cuerpo tubular</b> o <b>Tubo interior</b> y des\u00edgnelo como porta motor en la pesta\u00f1a <em>Motor</em>.
|
||||
|
||||
RocketComponent.Position.ABSOLUTE = Extremo de la ojiva
|
||||
RocketComponent.Position.AFTER = Despu\u00e9s del componente
|
||||
RocketComponent.Position.BOTTOM = Extremo inferior del componente
|
||||
@ -1705,7 +1708,6 @@ update.dlg.latestVersion = Usted est\u00e1 utilizando la \u00faltima versi\u00f3
|
||||
|
||||
ringcompcfg.Automatic = Autom\u00e1tico
|
||||
ringcompcfg.Distancefrom = Distancia desde la l\u00ednea central del cohete:
|
||||
ringcompcfg.EngineBlock.desc = <html>Un <b>ret\u00e9n de motor</b> impide que el motor se desplace hacia delante, por dentro del tubo porta motor.<br><br>Para a\u00f1adir un motor, cree un <b>Cuerpo tubular</b> o <b>Tubo interior</b> y des\u00edgnelo como porta motor en la pesta\u00f1a <em>Motor</em>.
|
||||
ringcompcfg.InnerRadius = Radio interior:
|
||||
ringcompcfg.Length = Longitud:
|
||||
! Ring Component Config
|
||||
|
||||
@ -861,6 +861,9 @@ RocketCompCfg.title.Noseconeshoulder = Epaulement du c\u00F4ne
|
||||
RocketCompCfg.ttip.Endcapped = Pr\u00E9cise si l'arri\u00E8re du c\u00F4ne est clos.
|
||||
RocketCompCfg.lbl.Componentname.ttip = Le nom de la pi\u00E8ce.
|
||||
|
||||
! ComponentInfo
|
||||
ComponentInfo.EngineBlock = Un <b>bloc moteur </b> emp\u00EAche le moteur de se d\u00E9placer vers l'avant dans le tube porte moteur.<br><br>Pour ajouter un moteur, cr\u00E9er un <b>tube</b> ou un <b>tube interne</b> et marquer le comme porte moteur dans l'onglet <em>Moteur</em>.
|
||||
|
||||
RocketComponent.Position.ABSOLUTE = Pointe de l'ogive
|
||||
RocketComponent.Position.AFTER = Apr\u00E8s la pi\u00E8ce parente
|
||||
RocketComponent.Position.BOTTOM = Bas de la pi\u00E8ce parente
|
||||
@ -1696,7 +1699,6 @@ update.dlg.latestVersion = Vous utilisez la derni\u00E8re version d'OpenRocket,
|
||||
|
||||
ringcompcfg.Automatic = Automatique
|
||||
ringcompcfg.Distancefrom = Distance de l'axe central de la fus\u00E9e
|
||||
ringcompcfg.EngineBlock.desc = <html>Un <b>bloc moteur </b> emp\u00EAche le moteur de se d\u00E9placer vers l'avant dans le tube porte moteur.<br><br>Pour ajouter un moteur, cr\u00E9er un <b>tube</b> ou un <b>tube interne</b> et marquer le comme porte moteur dans l'onglet <em>Moteur</em>.
|
||||
ringcompcfg.InnerRadius = Diam\u00E8tre int\u00E9rieur
|
||||
ringcompcfg.Length = Longueur
|
||||
! Ring Component Config
|
||||
|
||||
@ -626,7 +626,6 @@ ringcompcfg.Radialdirection = direzione Radiale:
|
||||
ringcompcfg.radialdirectionfrom = La direzione radiale dall linea centrale del razzo
|
||||
ringcompcfg.but.Reset = Azzera
|
||||
ringcompcfg.but.Resetcomponant = Azzera il componente alla linea centrale del razzo
|
||||
ringcompcfg.EngineBlock.desc = <html>Un <b>blocca motore</b> ferma il motore dal movimento in avanti nel tubo di montaggio del motore.<br><br>Per aggiungere un motore, crea un <b>corpo</b> o un <b>tubo interno</b> e segnalo come tubo di montaggio motore nella scheda <em>Motore</em> .
|
||||
ringcompcfg.note.desc = Nota: Un tubo interno non modifica l'aerodinamica del razzo anche se e' posto all'esterno del corpo.
|
||||
|
||||
|
||||
@ -720,6 +719,9 @@ RocketCompCfg.title.Aftshoulder = Spalla posteriore
|
||||
RocketCompCfg.border.Foreshoulder = Spalla anteriore
|
||||
!RocketCompCfg.lbl.Length = Lunghezza:
|
||||
|
||||
! ComponentInfo
|
||||
ComponentInfo.EngineBlock = Un <b>blocca motore</b> ferma il motore dal movimento in avanti nel tubo di montaggio del motore.<br><br>Per aggiungere un motore, crea un <b>corpo</b> o un <b>tubo interno</b> e segnalo come tubo di montaggio motore nella scheda <em>Motore</em> .
|
||||
|
||||
! BulkheadConfig
|
||||
BulkheadCfg.tab.Diameter = Diametro:
|
||||
BulkheadCfg.tab.Thickness = Spessore:
|
||||
|
||||
@ -656,7 +656,6 @@ ringcompcfg.Radialdirection = \u534A\u5F84\u65B9\u5411\u5411\u304D
|
||||
ringcompcfg.radialdirectionfrom = \u30ED\u30B1\u30C3\u30C8\u30BB\u30F3\u30BF\u30FC\u30E9\u30A4\u30F3\u304B\u3089\u306E\u534A\u5F84\u65B9\u5411\u306E\u5411\u304D
|
||||
ringcompcfg.but.Reset = \u30EA\u30BB\u30C3\u30C8
|
||||
ringcompcfg.but.Resetcomponant = \u90E8\u54C1\u3092\u30ED\u30B1\u30C3\u30C8\u30BB\u30F3\u30BF\u30FC\u30E9\u30A4\u30F3\u306B\u30EA\u30BB\u30C3\u30C8\u3059\u308B
|
||||
ringcompcfg.EngineBlock.desc = <html><b>\u30A8\u30F3\u30B8\u30F3\u30D6\u30ED\u30C3\u30AF</b>\u306F\u30E2\u30FC\u30BF\u30FC\u30DE\u30A6\u30F3\u30C8\u30C1\u30E5\u30FC\u30D6\u306E\u4E2D\u3067\u30E2\u30FC\u30BF\u30FC\u304C\u524D\u306B\u52D5\u304F\u306E\u3092\u6B62\u3081\u308B\u5F79\u5272\u3002<br><br>\u30E2\u30FC\u30BF\u30FC\u3092\u8FFD\u52A0\u3059\u308B\u306B\u306F <b>\u30DC\u30C7\u30A3\u30C1\u30E5\u30FC\u30D6</b>\u3082\u3057\u304F\u306F<b>\u30A4\u30F3\u30CA\u30FC\u30C1\u30E5\u30FC\u30D6</b>\u3092\u4F5C\u3063\u3066 and mark it as a motor mount in the <em>\u30E2\u30FC\u30BF\u30FC</em>\u30BF\u30D6\u3067\u30E2\u30FC\u30BF\u30FC\u30DE\u30A6\u30F3\u30C8\u3068\u3057\u3066\u30C1\u30A7\u30C3\u30AF\u3059\u308B\u3002
|
||||
ringcompcfg.note.desc = \u30E1\u30E2\uFF1A\u30A4\u30F3\u30CA\u30FC\u30C1\u30E5\u30FC\u30D6\u306F\u30DC\u30C7\u30A3\u30C1\u30E5\u30FC\u30D6\u306E\u5916\u5074\u306B\u51FA\u306A\u3044\u9650\u308A\u306F\u7A7A\u529B\u3078\u306E\u5F71\u97FF\u306F\u7121\u3044
|
||||
|
||||
|
||||
@ -750,6 +749,9 @@ RocketCompCfg.title.Aftshoulder = \u5F8C\u65B9\u30B7\u30E7\u30EB\u30C0\u30FC
|
||||
RocketCompCfg.border.Foreshoulder = \u524D\u65B9\u30B7\u30E7\u30EB\u30C0\u30FC
|
||||
!RocketCompCfg.lbl.Length
|
||||
|
||||
! ComponentInfo
|
||||
ComponentInfo.EngineBlock = <b>\u30A8\u30F3\u30B8\u30F3\u30D6\u30ED\u30C3\u30AF</b>\u306F\u30E2\u30FC\u30BF\u30FC\u30DE\u30A6\u30F3\u30C8\u30C1\u30E5\u30FC\u30D6\u306E\u4E2D\u3067\u30E2\u30FC\u30BF\u30FC\u304C\u524D\u306B\u52D5\u304F\u306E\u3092\u6B62\u3081\u308B\u5F79\u5272\u3002<br><br>\u30E2\u30FC\u30BF\u30FC\u3092\u8FFD\u52A0\u3059\u308B\u306B\u306F <b>\u30DC\u30C7\u30A3\u30C1\u30E5\u30FC\u30D6</b>\u3082\u3057\u304F\u306F<b>\u30A4\u30F3\u30CA\u30FC\u30C1\u30E5\u30FC\u30D6</b>\u3092\u4F5C\u3063\u3066 and mark it as a motor mount in the <em>\u30E2\u30FC\u30BF\u30FC</em>\u30BF\u30D6\u3067\u30E2\u30FC\u30BF\u30FC\u30DE\u30A6\u30F3\u30C8\u3068\u3057\u3066\u30C1\u30A7\u30C3\u30AF\u3059\u308B\u3002
|
||||
|
||||
! BulkheadConfig
|
||||
BulkheadCfg.tab.Diameter = \u534A\u5F84\uFF1A
|
||||
BulkheadCfg.tab.Thickness = \u539A\u3055\uFF1A
|
||||
@ -1046,7 +1048,7 @@ TCMotorSelPan.lbl.Datapoints = \u30C7\u30FC\u30BF\u70B9\uFF1A
|
||||
TCMotorSelPan.lbl.Digest = \u30C0\u30A4\u30B8\u30A7\u30B9\u30C8\uFF1A
|
||||
TCMotorSelPan.title.Thrustcurve = \u63A8\u529B\u5C65\u6B74\uFF1A
|
||||
TCMotorSelPan.title.Thrust = \u63A8\u529B
|
||||
TCMotorSelPan.delayBox.None = None
|
||||
TCMotorSelPan.delayBox.None = Plugged (none)
|
||||
TCMotorSelPan.noDescription = No description available.
|
||||
|
||||
|
||||
|
||||
@ -751,7 +751,6 @@ ringcompcfg.Radialdirection = Radiale richting:
|
||||
ringcompcfg.radialdirectionfrom = De radiale richting vanaf de middellijn van de raket
|
||||
ringcompcfg.but.Reset = Herstel
|
||||
ringcompcfg.but.Resetcomponant = Zet het onderdeel terug naar de raketmiddellijn
|
||||
ringcompcfg.EngineBlock.desc = <html>Een <b>motorblok</b> voorkomt dat de motor voorwaarts beweegt in de buis van de motorsteun.<br><br>Om een motor toe te voegen, maak een <b>rompbuis</b> of <b>binnenbuis</b> en markeer het als een motorbevestiging in het <em>Motortabblad</em>.
|
||||
ringcompcfg.note.desc = Opmerking: Een binnenbuis heeft geen invloed op de aërodynamica van de raket, zelfs niet als hij buiten de rompbuis is geplaatst.
|
||||
|
||||
|
||||
@ -871,6 +870,9 @@ RocketCompCfg.border.Foreshoulder = Voorschouder
|
||||
RocketCompCfg.lbl.InstanceCount = Aantal instanties
|
||||
RocketCompCfg.lbl.InstanceSeparation = Instantie afscheiding
|
||||
|
||||
! ComponentInfo
|
||||
ComponentInfo.EngineBlock = Een <b>motorblok</b> voorkomt dat de motor voorwaarts beweegt in de buis van de motorsteun.<br><br>Om een motor toe te voegen, maak een <b>rompbuis</b> of <b>binnenbuis</b> en markeer het als een motorbevestiging in het <em>Motortabblad</em>.
|
||||
|
||||
! BulkheadConfig
|
||||
BulkheadCfg.tab.Diameter = Diameter:
|
||||
BulkheadCfg.tab.Thickness = Dikte:
|
||||
|
||||
@ -570,7 +570,6 @@ update.dlg.latestVersion = Korzystasz z najnowszej wersji OpenRocket: %s.
|
||||
ringcompcfg.radialdirectionfrom = Kierunek prostopad\u0142y do osi centralnej rakiety
|
||||
ringcompcfg.but.Reset = Reset
|
||||
ringcompcfg.but.Resetcomponant = Resetuj po\u0142o\u017Cenie cz\u0119\u015Bci wzgl\u0119dem osi rakiety
|
||||
ringcompcfg.EngineBlock.desc = <html><b>Blokada silnika</b> unieruchamia silnik wewn\u0105trz elementu pe\u0142ni\u0105cego funkcj\u0119 gniazda silnikowego.<br><br>Aby doda\u0107 silnik, stwórz najpierw <b>Korpus rakiety</b> lub <b>rur\u0119 wewn\u0119trzn\u0105</b> i oznacz j\u0105 jako gniazdo silnika w zak\u0142adce <em>Silnik</em>.
|
||||
ringcompcfg.note.desc = Uwaga: Rura wewn\u0119trzna nie wp\u0142ywa na aerodynamik\u0119 rakiety, nawet je\u017Celi znajduje si\u0119 poza korpusem.
|
||||
|
||||
|
||||
@ -662,7 +661,11 @@ update.dlg.latestVersion = Korzystasz z najnowszej wersji OpenRocket: %s.
|
||||
RocketCompCfg.title.Noseconeshoulder = Wpust g\u0142owicy
|
||||
RocketCompCfg.title.Aftshoulder = Wpust tylny
|
||||
RocketCompCfg.border.Foreshoulder = Wpust przedni
|
||||
!RocketCompCfg.lbl.Length
|
||||
!RocketCompCfg.lbl.Length
|
||||
|
||||
! ComponentInfo
|
||||
ComponentInfo.EngineBlock = <b>Blokada silnika</b> unieruchamia silnik wewn\u0105trz elementu pe\u0142ni\u0105cego funkcj\u0119 gniazda silnikowego.<br><br>Aby doda\u0107 silnik, stwórz najpierw <b>Korpus rakiety</b> lub <b>rur\u0119 wewn\u0119trzn\u0105</b> i oznacz j\u0105 jako gniazdo silnika w zak\u0142adce <em>Silnik</em>.
|
||||
|
||||
|
||||
! BulkheadConfig
|
||||
BulkheadCfg.tab.Diameter = \u015Arednica:
|
||||
|
||||
@ -844,6 +844,9 @@ RocketCompCfg.title.Noseconeshoulder = Ressalto da ogiva
|
||||
RocketCompCfg.ttip.Endcapped = Quando a extremidade do ressalto \u00e9 limitada.
|
||||
RocketCompCfg.lbl.Componentname.ttip = Nome do componente.
|
||||
|
||||
! ComponentInfo
|
||||
ComponentInfo.EngineBlock = Um <b>bloco do motor</b> p\u00e1ra o motor de se mover para a frente no tubo de montagem do motor.<br><br>Para adicionar um motor, criar um <b>tubo de corpo</b> ou <b>tubo interno</b> e marc\u00e1-lo como uma montagem do motor na aba <em>Motor</em>.
|
||||
|
||||
RocketComponent.Position.ABSOLUTE = Dica da ogiva
|
||||
RocketComponent.Position.AFTER = Depois do componente pai
|
||||
RocketComponent.Position.BOTTOM = Parte do componente pai
|
||||
@ -1650,7 +1653,6 @@ update.dlg.latestVersion = Voc\u00ea est\u00e1 executando a vers\u00e3o mais rec
|
||||
|
||||
ringcompcfg.Automatic = Autom\u00e1tico
|
||||
ringcompcfg.Distancefrom = Dist\u00e2ncia a partir da linha de centro do foguete
|
||||
ringcompcfg.EngineBlock.desc = <html>Um <b>bloco do motor</b> p\u00e1ra o motor de se mover para a frente no tubo de montagem do motor.<br><br>Para adicionar um motor, criar um <b>tubo de corpo</b> ou <b>tubo interno</b> e marc\u00e1-lo como uma montagem do motor na aba <em>Motor</em>.
|
||||
ringcompcfg.InnerRadius = Raio interno
|
||||
ringcompcfg.Length = Comprimento
|
||||
# Ring Component Config
|
||||
|
||||
@ -804,7 +804,6 @@ ringcompcfg.Radialdirection = \u0420\u0430\u0434\u0438\u0430\u043B\u044C\u043D\u
|
||||
ringcompcfg.radialdirectionfrom = \u0420\u0430\u0434\u0438\u0430\u043B\u044C\u043D\u043E\u0435 \u043D\u0430\u043F\u0440\u0430\u0432\u043B\u0435\u043D\u0438\u0435 \u043E\u0442 \u043E\u0441\u0438 \u0440\u0430\u043A\u0435\u0442\u044B
|
||||
ringcompcfg.but.Reset = \u0421\u0431\u0440\u043E\u0441
|
||||
ringcompcfg.but.Resetcomponant = \u0412\u043E\u0441\u0441\u0442\u0430\u043D\u043E\u0432\u0438\u0442\u044C \u043A\u043E\u043C\u043F\u043E\u043D\u0435\u043D\u0442 \u043D\u0430 \u043E\u0441\u0438 \u0440\u0430\u043A\u0435\u0442\u044B
|
||||
ringcompcfg.EngineBlock.desc = <html><b>\u0423\u043F\u043E\u0440 \u0434\u0432\u0438\u0433\u0430\u0442\u0435\u043B\u044F</b> \u043F\u0440\u0435\u043F\u044F\u0442\u0441\u0442\u0432\u0443\u0435\u0442 \u0434\u0432\u0438\u0436\u0435\u043D\u0438\u044E \u0434\u0432\u0438\u0433\u0430\u0442\u0435\u043B\u044F \u0432\u043F\u0435\u0440\u0435\u0434 \u0432 \u0442\u0440\u0443\u0431\u0435.<br><br>\u0414\u043B\u044F \u0442\u043E\u0433\u043E \u0447\u0442\u043E\u0431\u044B \u0434\u043E\u0431\u0430\u0432\u0438\u0442\u044C \u0434\u0432\u0438\u0433\u0430\u0442\u0435\u043B\u044C, \u0441\u043E\u0437\u0434\u0430\u0439\u0442\u0435 <b>\u041A\u043E\u0440\u043F\u0443\u0441\u043D\u0443\u044E \u0442\u0440\u0443\u0431\u0443</b> \u0438\u043B\u0438 <b>\u0412\u043D\u0443\u0442\u0440\u0435\u043D\u043D\u044E\u044E \u0442\u0440\u0443\u0431\u0443</b> \u0438 \u043E\u0442\u043C\u0435\u0442\u044C\u0442\u0435 \u044D\u0442\u043E\u0442 \u044D\u043B\u0435\u043C\u0435\u043D\u0442 \u043A\u0430\u043A \u043A\u0440\u0435\u043F\u0435\u0436 \u0434\u0432\u0438\u0433\u0430\u0442\u0435\u043B\u044F \u043D\u0430 \u0432\u043A\u043B\u0430\u0434\u043A\u0435 <em>\u0414\u0432\u0438\u0433\u0430\u0442\u0435\u043B\u044C</em> .
|
||||
ringcompcfg.note.desc = \u041F\u0440\u0438\u043C\u0435\u0447\u0430\u043D\u0438\u0435: \u0412\u043D\u0443\u0442\u0440\u0435\u043D\u043D\u044F\u044F \u0442\u0440\u0443\u0431\u0430 \u043D\u0435 \u0432\u043B\u0438\u044F\u0435\u0442 \u043D\u0430 \u0430\u044D\u0440\u043E\u0434\u0438\u043D\u0430\u043C\u0438\u043A\u0443, \u0434\u0430\u0436\u0435 \u0431\u0443\u0434\u0443\u0447\u0438 \u0440\u0430\u0437\u043C\u0435\u0449\u0435\u043D\u043D\u043E\u0439 \u0437\u0430 \u043F\u0440\u0435\u0434\u0435\u043B\u0430\u043C\u0438 \u043A\u043E\u0440\u043F\u0443\u0441\u0430.
|
||||
|
||||
|
||||
@ -949,6 +948,9 @@ RocketCompCfg.tab.Inside = \u0412\u043D\u0443\u0442\u0440\u0438
|
||||
RocketCompCfg.tab.RightSide = \u0421\u043F\u0440\u0430\u0432\u0430
|
||||
RocketCompCfg.tab.LeftSide = \u0421\u043B\u0435\u0432\u0430
|
||||
|
||||
! ComponentInfo
|
||||
ComponentInfo.EngineBlock = <b>\u0423\u043F\u043E\u0440 \u0434\u0432\u0438\u0433\u0430\u0442\u0435\u043B\u044F</b> \u043F\u0440\u0435\u043F\u044F\u0442\u0441\u0442\u0432\u0443\u0435\u0442 \u0434\u0432\u0438\u0436\u0435\u043D\u0438\u044E \u0434\u0432\u0438\u0433\u0430\u0442\u0435\u043B\u044F \u0432\u043F\u0435\u0440\u0435\u0434 \u0432 \u0442\u0440\u0443\u0431\u0435.<br><br>\u0414\u043B\u044F \u0442\u043E\u0433\u043E \u0447\u0442\u043E\u0431\u044B \u0434\u043E\u0431\u0430\u0432\u0438\u0442\u044C \u0434\u0432\u0438\u0433\u0430\u0442\u0435\u043B\u044C, \u0441\u043E\u0437\u0434\u0430\u0439\u0442\u0435 <b>\u041A\u043E\u0440\u043F\u0443\u0441\u043D\u0443\u044E \u0442\u0440\u0443\u0431\u0443</b> \u0438\u043B\u0438 <b>\u0412\u043D\u0443\u0442\u0440\u0435\u043D\u043D\u044E\u044E \u0442\u0440\u0443\u0431\u0443</b> \u0438 \u043E\u0442\u043C\u0435\u0442\u044C\u0442\u0435 \u044D\u0442\u043E\u0442 \u044D\u043B\u0435\u043C\u0435\u043D\u0442 \u043A\u0430\u043A \u043A\u0440\u0435\u043F\u0435\u0436 \u0434\u0432\u0438\u0433\u0430\u0442\u0435\u043B\u044F \u043D\u0430 \u0432\u043A\u043B\u0430\u0434\u043A\u0435 <em>\u0414\u0432\u0438\u0433\u0430\u0442\u0435\u043B\u044C</em> .
|
||||
|
||||
! BulkheadConfig
|
||||
BulkheadCfg.tab.Diameter = \u0414\u0438\u0430\u043C\u0435\u0442\u0440:
|
||||
BulkheadCfg.tab.Thickness = \u0422\u043E\u043B\u0449\u0438\u043D\u0430:
|
||||
|
||||
@ -703,7 +703,6 @@ ringcompcfg.Radialdirection = Radial direction:
|
||||
ringcompcfg.radialdirectionfrom = The radial direction from the rocket centerline
|
||||
ringcompcfg.but.Reset = Reset
|
||||
ringcompcfg.but.Resetcomponant = Reset the component to the rocket centerline
|
||||
ringcompcfg.EngineBlock.desc = <html>An <b>engine block</b> stops the motor from moving forwards in the motor mount tube.<br><br>In order to add a motor, create a <b>body tube</b> or <b>inner tube</b> and mark it as a motor mount in the <em>Motor</em> tab.
|
||||
ringcompcfg.note.desc = Note: An inner tube will not affect the aerodynamics of the rocket even if it is located outside of the body tube.
|
||||
|
||||
|
||||
@ -822,6 +821,9 @@ RocketCompCfg.title.Aftshoulder = Aft shoulder
|
||||
RocketCompCfg.border.Foreshoulder = Fore shoulder
|
||||
!RocketCompCfg.lbl.Length = Length:
|
||||
|
||||
! ComponentInfo
|
||||
ComponentInfo.EngineBlock = An <b>engine block</b> stops the motor from moving forwards in the motor mount tube.<br><br>In order to add a motor, create a <b>body tube</b> or <b>inner tube</b> and mark it as a motor mount in the <em>Motor</em> tab.
|
||||
|
||||
! BulkheadConfig
|
||||
BulkheadCfg.tab.Diameter = Diameter:
|
||||
BulkheadCfg.tab.Thickness = Thickness:
|
||||
@ -1119,7 +1121,7 @@ TCMotorSelPan.lbl.Datapoints = Data points:
|
||||
TCMotorSelPan.lbl.Digest = Digest:
|
||||
TCMotorSelPan.title.Thrustcurve = Thrust curve:
|
||||
TCMotorSelPan.title.Thrust = Thrust
|
||||
TCMotorSelPan.delayBox.None = None
|
||||
TCMotorSelPan.delayBox.None = Plugged (none)
|
||||
TCMotorSelPan.noDescription = No description available.
|
||||
TCMotorSelPan.btn.checkAll = Select All
|
||||
TCMotorSelPan.btn.checkNone = Clear All
|
||||
|
||||
@ -933,6 +933,9 @@ RocketCompCfg.title.Noseconeshoulder = \u5934\u9525\u8FDE\u63A5\u59
|
||||
RocketCompCfg.ttip.Endcapped = \u8FDE\u63A5\u5904\u7EC8\u7AEF\u662F\u5426\u6709\u76D6.
|
||||
RocketCompCfg.lbl.Componentname.ttip = \u7EC4\u4EF6\u540D\u79F0.
|
||||
|
||||
! ComponentInfo
|
||||
ComponentInfo.EngineBlock = <b>\u53D1\u52A8\u673A\u5EA7</b>\u7528\u4E8E\u9632\u6B62\u53D1\u52A8\u673A\u5411\u524D\u7A9C\u51FA\u7BAD\u4F53.<br><br>\u6DFB\u52A0\u53D1\u52A8\u673A\u524D\u8BF7\u5148\u6DFB\u52A0<b>\u7BAD\u4F53</b>\u6216<b>\u5185\u7BA1</b>\u5E76\u5728<em>\u53D1\u52A8\u673A</em>\u9875\u9762\u4E0A\u6807\u8BB0\u4E3A\u53D1\u52A8\u673A\u5EA7.
|
||||
|
||||
RocketComponent.Position.ABSOLUTE = \u5934\u9525\u5C16\u7AEF
|
||||
RocketComponent.Position.AFTER = \u7236\u7EC4\u4EF6\u4E4B\u540E
|
||||
RocketComponent.Position.BOTTOM = \u7236\u7EC4\u4EF6\u5E95\u90E8
|
||||
@ -1787,7 +1790,6 @@ update.dlg.latestVersion = \u60A8\u4F7F\u7528\u7684\u5DF2\u7ECF\u662FOpenRocket\
|
||||
|
||||
ringcompcfg.Automatic = \u81EA\u52A8
|
||||
ringcompcfg.Distancefrom = \u5230\u706B\u7BAD\u4E2D\u5FC3\u7EBF\u7684\u8DDD\u79BB
|
||||
ringcompcfg.EngineBlock.desc = <html><b>\u53D1\u52A8\u673A\u5EA7</b>\u7528\u4E8E\u9632\u6B62\u53D1\u52A8\u673A\u5411\u524D\u7A9C\u51FA\u7BAD\u4F53.<br><br>\u6DFB\u52A0\u53D1\u52A8\u673A\u524D\u8BF7\u5148\u6DFB\u52A0<b>\u7BAD\u4F53</b>\u6216<b>\u5185\u7BA1</b>\u5E76\u5728<em>\u53D1\u52A8\u673A</em>\u9875\u9762\u4E0A\u6807\u8BB0\u4E3A\u53D1\u52A8\u673A\u5EA7.
|
||||
ringcompcfg.InnerRadius = \u5185\u76F4\u5F84
|
||||
ringcompcfg.Length = \u957F\u5EA6
|
||||
! Ring Component Config
|
||||
|
||||
|
Before Width: | Height: | Size: 13 KiB After Width: | Height: | Size: 12 KiB |
|
Before Width: | Height: | Size: 624 B After Width: | Height: | Size: 649 B |
|
Before Width: | Height: | Size: 2.0 KiB After Width: | Height: | Size: 2.6 KiB |
|
Before Width: | Height: | Size: 3.8 KiB After Width: | Height: | Size: 4.3 KiB |
|
Before Width: | Height: | Size: 5.8 KiB After Width: | Height: | Size: 6.3 KiB |
BIN
core/resources/pix/icon/icon-128.png
Normal file
|
After Width: | Height: | Size: 18 KiB |
|
Before Width: | Height: | Size: 63 KiB After Width: | Height: | Size: 53 KiB |
|
Before Width: | Height: | Size: 39 KiB |
|
Before Width: | Height: | Size: 871 KiB After Width: | Height: | Size: 136 KiB |
@ -69,7 +69,7 @@ public interface AerodynamicCalculator extends Monitorable {
|
||||
public AerodynamicCalculator newInstance();
|
||||
|
||||
/**
|
||||
* Test component assembly for continuity (esp. diameter), and post any needed warnings
|
||||
* Check component assembly for geometric problems and post any needed warnings
|
||||
*/
|
||||
public void testIsContinuous(FlightConfiguration configuration, final RocketComponent component, WarningSet warnings);
|
||||
public void checkGeometry(FlightConfiguration configuration, final RocketComponent component, WarningSet warnings);
|
||||
}
|
||||
|
||||
@ -21,6 +21,7 @@ import net.sf.openrocket.rocketcomponent.InstanceMap;
|
||||
import net.sf.openrocket.rocketcomponent.Rocket;
|
||||
import net.sf.openrocket.rocketcomponent.RocketComponent;
|
||||
import net.sf.openrocket.rocketcomponent.SymmetricComponent;
|
||||
import net.sf.openrocket.unit.UnitGroup;
|
||||
import net.sf.openrocket.util.Coordinate;
|
||||
import net.sf.openrocket.util.MathUtil;
|
||||
import net.sf.openrocket.util.PolyInterpolator;
|
||||
@ -44,7 +45,6 @@ public class BarrowmanCalculator extends AbstractAerodynamicCalculator {
|
||||
private double cacheDiameter = -1;
|
||||
private double cacheLength = -1;
|
||||
|
||||
|
||||
public BarrowmanCalculator() {
|
||||
|
||||
}
|
||||
@ -252,7 +252,7 @@ public class BarrowmanCalculator extends AbstractAerodynamicCalculator {
|
||||
if (calcMap == null)
|
||||
buildCalcMap(configuration);
|
||||
|
||||
testIsContinuous(configuration, configuration.getRocket(), warnings);
|
||||
checkGeometry(configuration, configuration.getRocket(), warnings);
|
||||
|
||||
final InstanceMap imap = configuration.getActiveInstances();
|
||||
|
||||
@ -276,7 +276,7 @@ public class BarrowmanCalculator extends AbstractAerodynamicCalculator {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void testIsContinuous(FlightConfiguration configuration, final RocketComponent treeRoot, WarningSet warnings ){
|
||||
public void checkGeometry(FlightConfiguration configuration, final RocketComponent treeRoot, WarningSet warnings ){
|
||||
Queue<RocketComponent> queue = new LinkedList<>();
|
||||
for (RocketComponent child : treeRoot.getChildren()) {
|
||||
// Ignore inactive stages
|
||||
@ -299,14 +299,20 @@ public class BarrowmanCalculator extends AbstractAerodynamicCalculator {
|
||||
}
|
||||
|
||||
SymmetricComponent sym = (SymmetricComponent) comp;
|
||||
prevComp = sym.getPreviousSymmetricComponent();
|
||||
if( null == prevComp){
|
||||
prevComp = sym;
|
||||
continue;
|
||||
}
|
||||
|
||||
// Check for radius discontinuity
|
||||
if ( !MathUtil.equals(sym.getForeRadius(), prevComp.getAftRadius())) {
|
||||
warnings.add( Warning.DIAMETER_DISCONTINUITY, sym + ", " + prevComp);
|
||||
if (sym.getForeRadius() - sym.getThickness() > MathUtil.EPSILON) {
|
||||
warnings.add(Warning.OPEN_AIRFRAME_FORWARD, sym.toString());
|
||||
}
|
||||
} else {
|
||||
// Check for radius discontinuity
|
||||
// We're going to say it's discontinuous if it is presented to the user as having two different
|
||||
// string representations. Hopefully there are enough digits in the string that it will
|
||||
// present as different if the discontinuity is big enough to matter.
|
||||
if (!UnitGroup.UNITS_LENGTH.getDefaultUnit().toStringUnit(2.0*sym.getForeRadius()).equals(UnitGroup.UNITS_LENGTH.getDefaultUnit().toStringUnit(2.0*prevComp.getAftRadius()))) {
|
||||
// if ( !MathUtil.equals(sym.getForeRadius(), prevComp.getAftRadius())) {
|
||||
warnings.add( Warning.DIAMETER_DISCONTINUITY, sym + ", " + prevComp);
|
||||
}
|
||||
}
|
||||
|
||||
// double x = component.toAbsolute(Coordinate.NUL)[0].x;
|
||||
@ -318,9 +324,8 @@ public class BarrowmanCalculator extends AbstractAerodynamicCalculator {
|
||||
//}
|
||||
//componentX = component.toAbsolute(new Coordinate(component.getLengthAerodynamic()))[0].x;
|
||||
|
||||
prevComp = sym;
|
||||
}else if( comp instanceof ComponentAssembly ){
|
||||
testIsContinuous(configuration, comp, warnings);
|
||||
checkGeometry(configuration, comp, warnings);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@ -358,6 +358,9 @@ public abstract class Warning {
|
||||
/** A <code>Warning</code> that the body diameter is discontinuous. */
|
||||
////Discontinuity in rocket body diameter.
|
||||
public static final Warning DIAMETER_DISCONTINUITY = new Other(trans.get("Warning.DISCONTINUITY"));
|
||||
|
||||
/** A <code>Warning</code> that a ComponentAssembly has an open forward end */
|
||||
public static final Warning OPEN_AIRFRAME_FORWARD = new Other(trans.get("Warning.OPEN_AIRFRAME_FORWARD"));
|
||||
|
||||
/** A <code>Warning</code> that the fins are thick compared to the rocket body. */
|
||||
////Thick fins may not be modeled accurately.
|
||||
|
||||
@ -0,0 +1,102 @@
|
||||
package net.sf.openrocket.aerodynamics.barrowman;
|
||||
|
||||
import java.util.List;
|
||||
import java.lang.Math;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import net.sf.openrocket.aerodynamics.AerodynamicForces;
|
||||
import net.sf.openrocket.aerodynamics.FlightConditions;
|
||||
import net.sf.openrocket.aerodynamics.WarningSet;
|
||||
import net.sf.openrocket.rocketcomponent.RailButton;
|
||||
import net.sf.openrocket.rocketcomponent.RocketComponent;
|
||||
import net.sf.openrocket.util.Coordinate;
|
||||
import net.sf.openrocket.util.MathUtil;
|
||||
import net.sf.openrocket.util.Transformation;
|
||||
|
||||
public class RailButtonCalc extends RocketComponentCalc {
|
||||
private final static Logger log = LoggerFactory.getLogger(RailButtonCalc.class);
|
||||
|
||||
// values transcribed from Gowen and Perkins, "Drag of Circular Cylinders for a Wide Range
|
||||
// of Reynolds Numbers and Mach Numbers", NACA Technical Note 2960, Figure 7
|
||||
private static final List<Double> cdDomain = List.of(0.0, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 1.0, 1.6, 2.0, 2.8, 100.0);
|
||||
private static final List<Double> cdRange = List.of(1.2, 1.22, 1.25, 1.3, 1.4, 1.5, 1.6, 2.1, 1.5, 1.45, 1.33, 1.33);
|
||||
|
||||
private final RailButton button;
|
||||
|
||||
public RailButtonCalc(RocketComponent component) {
|
||||
super(component);
|
||||
|
||||
// need to stash the button
|
||||
button = (RailButton) component;
|
||||
}
|
||||
|
||||
@Override
|
||||
public double calculateFrictionCD(FlightConditions conditions, double componentCf, WarningSet warnings) {
|
||||
// very small relative surface area, and slick
|
||||
return 0.0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void calculateNonaxialForces(FlightConditions conditions, Transformation transform,
|
||||
AerodynamicForces forces, WarningSet warnings) {
|
||||
// Nothing to be done
|
||||
}
|
||||
|
||||
@Override
|
||||
public double calculatePressureCD(FlightConditions conditions,
|
||||
double stagnationCD, double baseCD, WarningSet warnings) {
|
||||
|
||||
// grab relevant button params
|
||||
final int instanceCount = button.getInstanceCount();
|
||||
final Coordinate[] instanceOffsets = button.getInstanceOffsets();
|
||||
|
||||
// compute button reference area
|
||||
final double buttonHt = button.getTotalHeight();
|
||||
final double outerArea = buttonHt * button.getOuterDiameter();
|
||||
final double notchArea = (button.getOuterDiameter() - button.getInnerDiameter()) * button.getInnerHeight();
|
||||
final double refArea = outerArea - notchArea;
|
||||
|
||||
// accumulate Cd contribution from each rail button
|
||||
double CDmul = 0.0;
|
||||
for (int i = 0; i < button.getInstanceCount(); i++) {
|
||||
|
||||
// compute boundary layer height at button location. I can't find a good reference for the
|
||||
// formula, e.g. https://aerospaceengineeringblog.com/boundary-layers/ simply says it's the
|
||||
// "scientific consensus".
|
||||
double x = (button.toAbsolute(instanceOffsets[i]))[0].x; // location of button
|
||||
double rex = calculateReynoldsNumber(x, conditions); // Reynolds number of button location
|
||||
double del = 0.37 * x / Math.pow(rex, 0.2); // Boundary layer thickness
|
||||
|
||||
// compute mean airspeed over button
|
||||
// this assumes airspeed changes linearly through boundary layer
|
||||
// and that all parts of the railbutton contribute equally to Cd,
|
||||
// neither of which is true but both are plenty close enough for our purposes
|
||||
|
||||
double mach;
|
||||
if (buttonHt > del) {
|
||||
// Case 1: button extends beyond boundary layer
|
||||
// Mean velocity is 1/2 rocket velocity up to limit of boundary layer,
|
||||
// full velocity after that
|
||||
mach = (buttonHt - 0.5*del) * conditions.getMach()/buttonHt;
|
||||
} else {
|
||||
// Case 2: button is entirely within boundary layer
|
||||
mach = MathUtil.map(buttonHt/2.0, 0, del, 0, conditions.getMach());
|
||||
}
|
||||
|
||||
// look up Cd as function of speed. It's pretty constant as a function of Reynolds
|
||||
// number when slow, so we can just use a function of Mach number
|
||||
double cd = MathUtil.interpolate(cdDomain, cdRange, mach);
|
||||
|
||||
// Since later drag force calculations don't consider boundary layer, compute "effective Cd"
|
||||
// based on rocket velocity
|
||||
cd = cd * MathUtil.pow2(mach)/MathUtil.pow2(conditions.getMach());
|
||||
|
||||
// add to CDmul
|
||||
CDmul += cd;
|
||||
}
|
||||
|
||||
return CDmul * stagnationCD * refArea / conditions.getRefArea();
|
||||
}
|
||||
}
|
||||
@ -220,6 +220,9 @@ public class ThrustCurveMotorSet implements Comparable<ThrustCurveMotorSet> {
|
||||
(type != m.getMotorType())) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!designation.equalsIgnoreCase(m.getDesignation()))
|
||||
return false;
|
||||
|
||||
if (!commonName.equalsIgnoreCase(m.getCommonName()))
|
||||
return false;
|
||||
|
||||
@ -384,15 +384,19 @@ public class Simulation implements ChangeSource, Cloneable {
|
||||
simulatedData = simulator.simulate(simulationConditions);
|
||||
t2 = System.currentTimeMillis();
|
||||
log.debug("Simulation: returning from simulator, simulation took " + (t2 - t1) + "ms");
|
||||
|
||||
// Set simulated info after simulation, will not be set in case of exception
|
||||
|
||||
} catch (SimulationException e) {
|
||||
simulatedData = e.getFlightData();
|
||||
throw e;
|
||||
} finally {
|
||||
// Set simulated info after simulation
|
||||
simulatedConditions = options.clone();
|
||||
simulatedConfigurationDescription = descriptor.format( this.rocket, getId());
|
||||
simulatedRocketID = rocket.getFunctionalModID();
|
||||
|
||||
status = Status.UPTODATE;
|
||||
fireChangeEvent();
|
||||
} finally {
|
||||
|
||||
mutex.unlock("simulate");
|
||||
}
|
||||
}
|
||||
|
||||
@ -56,7 +56,7 @@ public class DirectoryIterator extends FileIterator {
|
||||
|
||||
|
||||
@Override
|
||||
protected Pair<String, InputStream> findNext() {
|
||||
protected Pair<File, InputStream> findNext() {
|
||||
|
||||
// Check if we're recursing
|
||||
if (subIterator != null) {
|
||||
@ -86,7 +86,7 @@ public class DirectoryIterator extends FileIterator {
|
||||
}
|
||||
|
||||
InputStream is = new BufferedInputStream(new FileInputStream(file));
|
||||
return new Pair<String, InputStream>(file.getName(), is);
|
||||
return new Pair<>(file, is);
|
||||
} catch (IOException e) {
|
||||
logger.warn("Error opening file/directory " + file, e);
|
||||
}
|
||||
|
||||
@ -1,5 +1,6 @@
|
||||
package net.sf.openrocket.file.iterator;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.util.Iterator;
|
||||
@ -20,10 +21,10 @@ import net.sf.openrocket.util.Pair;
|
||||
*
|
||||
* @author Sampo Niskanen <sampo.niskanen@iki.fi>
|
||||
*/
|
||||
public abstract class FileIterator implements Iterator<Pair<String, InputStream>> {
|
||||
public abstract class FileIterator implements Iterator<Pair<File, InputStream>> {
|
||||
private static final Logger logger = LoggerFactory.getLogger(FileIterator.class);
|
||||
|
||||
private Pair<String, InputStream> next = null;
|
||||
private Pair<File, InputStream> next = null;
|
||||
private int fileCount = 0;
|
||||
|
||||
@Override
|
||||
@ -37,7 +38,7 @@ public abstract class FileIterator implements Iterator<Pair<String, InputStream>
|
||||
|
||||
|
||||
@Override
|
||||
public Pair<String, InputStream> next() {
|
||||
public Pair<File, InputStream> next() {
|
||||
if (next == null) {
|
||||
next = findNext();
|
||||
}
|
||||
@ -45,7 +46,7 @@ public abstract class FileIterator implements Iterator<Pair<String, InputStream>
|
||||
throw new NoSuchElementException("No more files");
|
||||
}
|
||||
|
||||
Pair<String, InputStream> n = next;
|
||||
Pair<File, InputStream> n = next;
|
||||
next = null;
|
||||
fileCount++;
|
||||
return n;
|
||||
@ -86,10 +87,10 @@ public abstract class FileIterator implements Iterator<Pair<String, InputStream>
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the next pair of file name and InputStream.
|
||||
* Return the next pair of file and InputStream.
|
||||
*
|
||||
* @return a pair with the file name and input stream reading the file.
|
||||
* @return a pair with the file and input stream reading the file.
|
||||
*/
|
||||
protected abstract Pair<String, InputStream> findNext();
|
||||
protected abstract Pair<File, InputStream> findNext();
|
||||
|
||||
}
|
||||
|
||||
@ -78,7 +78,7 @@ public class ZipDirectoryIterator extends FileIterator {
|
||||
|
||||
|
||||
@Override
|
||||
protected Pair<String, InputStream> findNext() {
|
||||
protected Pair<File, InputStream> findNext() {
|
||||
if (entries == null) {
|
||||
return null;
|
||||
}
|
||||
@ -90,7 +90,7 @@ public class ZipDirectoryIterator extends FileIterator {
|
||||
if (name.startsWith(directory) && filter.accept(file)) {
|
||||
try {
|
||||
InputStream is = zipFile.getInputStream(entry);
|
||||
return new Pair<String, InputStream>(name, is);
|
||||
return new Pair<>(file, is);
|
||||
} catch (IOException e) {
|
||||
logger.error("IOException when reading ZIP file " + zipFileName, e);
|
||||
}
|
||||
|
||||
@ -44,7 +44,7 @@ public class ZipFileMotorLoader implements MotorLoader {
|
||||
|
||||
|
||||
@Override
|
||||
public List<ThrustCurveMotor.Builder> load(InputStream stream, String filename) throws IOException {
|
||||
public List<ThrustCurveMotor.Builder> load(InputStream stream, String filename) throws IOException, IllegalArgumentException {
|
||||
List<ThrustCurveMotor.Builder> motors = new ArrayList<>();
|
||||
|
||||
ZipInputStream is = new ZipInputStream(stream);
|
||||
|
||||
@ -10,9 +10,11 @@ import net.sf.openrocket.util.Reflection;
|
||||
//// BooleanSetter - set a boolean value
|
||||
class BooleanSetter implements Setter {
|
||||
private final Reflection.Method setMethod;
|
||||
private Object[] extraParameters = null;
|
||||
|
||||
public BooleanSetter(Reflection.Method set) {
|
||||
public BooleanSetter(Reflection.Method set, Object... parameters) {
|
||||
setMethod = set;
|
||||
this.extraParameters = parameters;
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -20,12 +22,23 @@ class BooleanSetter implements Setter {
|
||||
WarningSet warnings) {
|
||||
|
||||
s = s.trim();
|
||||
final boolean setValue;
|
||||
if (s.equalsIgnoreCase("true")) {
|
||||
setMethod.invoke(c, true);
|
||||
setValue = true;
|
||||
} else if (s.equalsIgnoreCase("false")) {
|
||||
setMethod.invoke(c, false);
|
||||
setValue = false;
|
||||
} else {
|
||||
warnings.add(Warning.FILE_INVALID_PARAMETER);
|
||||
return;
|
||||
}
|
||||
|
||||
if (extraParameters != null) {
|
||||
Object[] parameters = new Object[extraParameters.length + 1];
|
||||
parameters[0] = setValue;
|
||||
System.arraycopy(extraParameters, 0, parameters, 1, extraParameters.length);
|
||||
setMethod.invoke(c, parameters);
|
||||
} else {
|
||||
setMethod.invoke(c, setValue);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -248,7 +248,9 @@ class DocumentConfig {
|
||||
Reflection.findMethod(Transition.class, "setAftShoulderThickness", double.class)));
|
||||
setters.put("Transition:aftshouldercapped", new BooleanSetter(
|
||||
Reflection.findMethod(Transition.class, "setAftShoulderCapped", boolean.class)));
|
||||
|
||||
|
||||
setters.put("NoseCone:isflipped", new BooleanSetter(
|
||||
Reflection.findMethod(NoseCone.class, "setFlipped", boolean.class, boolean.class), false));
|
||||
// NoseCone - disable disallowed elements
|
||||
setters.put("NoseCone:foreradius", null);
|
||||
setters.put("NoseCone:foreshoulderradius", null);
|
||||
|
||||
@ -1,7 +1,10 @@
|
||||
package net.sf.openrocket.file.openrocket.savers;
|
||||
|
||||
import net.sf.openrocket.rocketcomponent.NoseCone;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
|
||||
public class NoseConeSaver extends TransitionSaver {
|
||||
|
||||
@ -20,8 +23,23 @@ public class NoseConeSaver extends TransitionSaver {
|
||||
|
||||
@Override
|
||||
protected void addParams(net.sf.openrocket.rocketcomponent.RocketComponent c, List<String> elements) {
|
||||
NoseCone noseCone = (NoseCone) c;
|
||||
super.addParams(c, elements);
|
||||
|
||||
// Transition handles nose cone saving as well
|
||||
|
||||
if (noseCone.isBaseRadiusAutomatic())
|
||||
elements.add("<aftradius>auto " + noseCone.getBaseRadiusNoAutomatic() + "</aftradius>");
|
||||
else
|
||||
elements.add("<aftradius>" + noseCone.getBaseRadius() + "</aftradius>");
|
||||
|
||||
elements.add("<aftshoulderradius>" + noseCone.getShoulderRadius()
|
||||
+ "</aftshoulderradius>");
|
||||
elements.add("<aftshoulderlength>" + noseCone.getShoulderLength()
|
||||
+ "</aftshoulderlength>");
|
||||
elements.add("<aftshoulderthickness>" + noseCone.getShoulderThickness()
|
||||
+ "</aftshoulderthickness>");
|
||||
elements.add("<aftshouldercapped>" + noseCone.isShoulderCapped()
|
||||
+ "</aftshouldercapped>");
|
||||
|
||||
elements.add("<isflipped>" + noseCone.isFlipped() + "</isflipped>");
|
||||
}
|
||||
}
|
||||
|
||||
@ -30,8 +30,6 @@ public class TransitionSaver extends SymmetricComponentSaver {
|
||||
protected void addParams(net.sf.openrocket.rocketcomponent.RocketComponent c, List<String> elements) {
|
||||
super.addParams(c, elements);
|
||||
net.sf.openrocket.rocketcomponent.Transition trans = (net.sf.openrocket.rocketcomponent.Transition) c;
|
||||
boolean nosecone = (trans instanceof NoseCone);
|
||||
|
||||
|
||||
Transition.Shape shape = trans.getType();
|
||||
elements.add("<shape>" + shape.name().toLowerCase(Locale.ENGLISH) + "</shape>");
|
||||
@ -41,14 +39,16 @@ public class TransitionSaver extends SymmetricComponentSaver {
|
||||
if (shape.usesParameter()) {
|
||||
elements.add("<shapeparameter>" + trans.getShapeParameter() + "</shapeparameter>");
|
||||
}
|
||||
|
||||
|
||||
if (!nosecone) {
|
||||
if (trans.isForeRadiusAutomatic())
|
||||
elements.add("<foreradius>auto " + trans.getForeRadiusNoAutomatic() + "</foreradius>");
|
||||
else
|
||||
elements.add("<foreradius>" + trans.getForeRadius() + "</foreradius>");
|
||||
|
||||
// Nose cones need other parameter saving, due to the isFlipped() parameter
|
||||
if (trans instanceof NoseCone) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (trans.isForeRadiusAutomatic())
|
||||
elements.add("<foreradius>auto " + trans.getForeRadiusNoAutomatic() + "</foreradius>");
|
||||
else
|
||||
elements.add("<foreradius>" + trans.getForeRadius() + "</foreradius>");
|
||||
|
||||
if (trans.isAftRadiusAutomatic())
|
||||
elements.add("<aftradius>auto " + trans.getAftRadiusNoAutomatic() + "</aftradius>");
|
||||
@ -56,16 +56,14 @@ public class TransitionSaver extends SymmetricComponentSaver {
|
||||
elements.add("<aftradius>" + trans.getAftRadius() + "</aftradius>");
|
||||
|
||||
|
||||
if (!nosecone) {
|
||||
elements.add("<foreshoulderradius>" + trans.getForeShoulderRadius()
|
||||
+ "</foreshoulderradius>");
|
||||
elements.add("<foreshoulderlength>" + trans.getForeShoulderLength()
|
||||
+ "</foreshoulderlength>");
|
||||
elements.add("<foreshoulderthickness>" + trans.getForeShoulderThickness()
|
||||
+ "</foreshoulderthickness>");
|
||||
elements.add("<foreshouldercapped>" + trans.isForeShoulderCapped()
|
||||
+ "</foreshouldercapped>");
|
||||
}
|
||||
elements.add("<foreshoulderradius>" + trans.getForeShoulderRadius()
|
||||
+ "</foreshoulderradius>");
|
||||
elements.add("<foreshoulderlength>" + trans.getForeShoulderLength()
|
||||
+ "</foreshoulderlength>");
|
||||
elements.add("<foreshoulderthickness>" + trans.getForeShoulderThickness()
|
||||
+ "</foreshoulderthickness>");
|
||||
elements.add("<foreshouldercapped>" + trans.isForeShoulderCapped()
|
||||
+ "</foreshouldercapped>");
|
||||
|
||||
elements.add("<aftshoulderradius>" + trans.getAftShoulderRadius()
|
||||
+ "</aftshoulderradius>");
|
||||
|
||||
@ -65,7 +65,11 @@ public class PodSetDTO extends BasePartDTO implements AttachableParts {
|
||||
} else if (child instanceof BodyTube) {
|
||||
addAttachedPart(new BodyTubeDTO((BodyTube) child));
|
||||
} else if (child instanceof NoseCone) {
|
||||
addAttachedPart(new NoseConeDTO((NoseCone) child));
|
||||
if (((NoseCone) child).isFlipped()) {
|
||||
addAttachedPart(new TransitionDTO((NoseCone) child));
|
||||
} else {
|
||||
addAttachedPart(new NoseConeDTO((NoseCone) child));
|
||||
}
|
||||
} else if (child instanceof Transition) {
|
||||
addAttachedPart(new TransitionDTO((Transition) child));
|
||||
}
|
||||
|
||||
@ -93,8 +93,12 @@ public class StageDTO {
|
||||
externalPart.add(theExternalPartDTO);
|
||||
}
|
||||
|
||||
private NoseConeDTO toNoseConeDTO(NoseCone nc) {
|
||||
return new NoseConeDTO(nc);
|
||||
private AbstractTransitionDTO toNoseConeDTO(NoseCone nc) {
|
||||
if (nc.isFlipped()) {
|
||||
return new TransitionDTO(nc);
|
||||
} else {
|
||||
return new NoseConeDTO(nc);
|
||||
}
|
||||
}
|
||||
|
||||
private BodyTubeDTO toBodyTubeDTO(BodyTube bt) {
|
||||
|
||||
@ -78,8 +78,16 @@ public class ClassBasedTranslator implements Translator {
|
||||
public String getBaseText(String base, String translation) {
|
||||
return translator.getBaseText(base, translation);
|
||||
}
|
||||
|
||||
|
||||
|
||||
@Override
|
||||
public boolean checkIfKeyExists(String key) {
|
||||
try {
|
||||
get(key);
|
||||
return true;
|
||||
} catch (MissingResourceException e) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
private String findClassName() {
|
||||
Throwable trace = new Throwable();
|
||||
|
||||
@ -1,5 +1,7 @@
|
||||
package net.sf.openrocket.l10n;
|
||||
|
||||
import java.util.MissingResourceException;
|
||||
|
||||
/**
|
||||
* A translator implementation that returns the logical key in brackets instead
|
||||
* of an actual translation. The class optionally verifies that the translation
|
||||
@ -47,6 +49,15 @@ public class DebugTranslator implements Translator {
|
||||
}
|
||||
return translation;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public boolean checkIfKeyExists(String key) {
|
||||
try {
|
||||
translator.get(key);
|
||||
return true;
|
||||
} catch (MissingResourceException e) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@ -52,7 +52,16 @@ public class ExceptionSuppressingTranslator implements Translator {
|
||||
public String getBaseText(String base, String translation) {
|
||||
return translator.getBaseText(base, translation);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public boolean checkIfKeyExists(String key) {
|
||||
try {
|
||||
translator.get(key);
|
||||
return true;
|
||||
} catch (MissingResourceException e) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
private static synchronized void handleError(String key, MissingResourceException e) {
|
||||
if (!errorReported) {
|
||||
|
||||
@ -66,4 +66,14 @@ public class ResourceBundleTranslator implements Translator {
|
||||
}
|
||||
return translation;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean checkIfKeyExists(String key) {
|
||||
try {
|
||||
get(key);
|
||||
return true;
|
||||
} catch (MissingResourceException e) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -50,5 +50,12 @@ public interface Translator {
|
||||
* @return the base text, or the translation if not found.
|
||||
*/
|
||||
public String getBaseText(String base, String translation);
|
||||
|
||||
/**
|
||||
* Checks whether a certain translation key exists.
|
||||
* @param key the key to check
|
||||
* @return true if it exists, false otherwise
|
||||
*/
|
||||
public boolean checkIfKeyExists(String key);
|
||||
|
||||
}
|
||||
|
||||
@ -56,7 +56,7 @@ public class DefaultSimulationModifierService implements SimulationModifierServi
|
||||
*/
|
||||
|
||||
addModifier("optimization.modifier.nosecone.length", UnitGroup.UNITS_LENGTH, 1.0, NoseCone.class, "Length");
|
||||
addModifier("optimization.modifier.nosecone.diameter", UnitGroup.UNITS_LENGTH, 2.0, NoseCone.class, "AftRadius", "isAftRadiusAutomatic");
|
||||
addModifier("optimization.modifier.nosecone.diameter", UnitGroup.UNITS_LENGTH, 2.0, NoseCone.class, "BaseRadius", "isBaseRadiusAutomatic");
|
||||
addModifier("optimization.modifier.nosecone.thickness", UnitGroup.UNITS_LENGTH, 1.0, NoseCone.class, "Thickness", "isFilled");
|
||||
|
||||
addModifier("optimization.modifier.transition.length", UnitGroup.UNITS_LENGTH, 1.0, Transition.class, "Length");
|
||||
|
||||
@ -241,6 +241,7 @@ public class AxialStage extends ComponentAssembly implements FlightConfigurableC
|
||||
@Override
|
||||
public void clearConfigListeners() {
|
||||
super.clearConfigListeners();
|
||||
// StageSeparationConfiguration also has config listeners, so clear them as well
|
||||
StageSeparationConfiguration thisConfig = getSeparationConfiguration();
|
||||
thisConfig.clearConfigListeners();
|
||||
}
|
||||
|
||||
@ -549,6 +549,7 @@ public class BodyTube extends SymmetricComponent implements BoxBounded, MotorMou
|
||||
@Override
|
||||
public void clearConfigListeners() {
|
||||
super.clearConfigListeners();
|
||||
// The motor config also has listeners, so clear them as well
|
||||
getDefaultMotorConfig().clearConfigListeners();
|
||||
}
|
||||
}
|
||||
|
||||
@ -482,6 +482,7 @@ public class InnerTube extends ThicknessRingComponent implements AxialPositionab
|
||||
@Override
|
||||
public void clearConfigListeners() {
|
||||
super.clearConfigListeners();
|
||||
// The motor config also has listeners, so clear them as well
|
||||
getDefaultMotorConfig().clearConfigListeners();
|
||||
}
|
||||
|
||||
|
||||
@ -1,18 +1,16 @@
|
||||
package net.sf.openrocket.rocketcomponent;
|
||||
|
||||
import net.sf.openrocket.appearance.Appearance;
|
||||
import net.sf.openrocket.appearance.Decal;
|
||||
import net.sf.openrocket.l10n.Translator;
|
||||
import net.sf.openrocket.preset.ComponentPreset;
|
||||
import net.sf.openrocket.preset.ComponentPreset.Type;
|
||||
import net.sf.openrocket.startup.Application;
|
||||
import net.sf.openrocket.util.StateChangeListener;
|
||||
|
||||
import java.util.EventObject;
|
||||
|
||||
/**
|
||||
* Rocket nose cones of various types. Implemented as a transition with the
|
||||
* fore radius == 0.
|
||||
* <p>
|
||||
* The normal nose cone can be converted to a tail cone by setting the {@link #isFlipped} parameter.
|
||||
* This will flip all the aft side dimensions with the fore side dimensions.
|
||||
*
|
||||
* @author Sampo Niskanen <sampo.niskanen@iki.fi>
|
||||
*/
|
||||
@ -21,6 +19,7 @@ public class NoseCone extends Transition implements InsideColorComponent {
|
||||
private static final Translator trans = Application.getTranslator();
|
||||
|
||||
private InsideColorComponentHandler insideColorComponentHandler = new InsideColorComponentHandler(this);
|
||||
private boolean isFlipped; // If true, the nose cone is converted to a tail cone
|
||||
|
||||
/********* Constructors **********/
|
||||
public NoseCone() {
|
||||
@ -29,16 +28,12 @@ public class NoseCone extends Transition implements InsideColorComponent {
|
||||
|
||||
public NoseCone(Transition.Shape type, double length, double radius) {
|
||||
super();
|
||||
this.isFlipped = false;
|
||||
super.setType(type);
|
||||
super.setForeRadiusAutomatic(false);
|
||||
super.setForeRadius(0);
|
||||
super.setForeShoulderLength(0);
|
||||
super.setForeShoulderRadius(0.9 * radius);
|
||||
super.setForeShoulderThickness(0);
|
||||
super.setForeShoulderCapped(filled);
|
||||
super.setThickness(0.002);
|
||||
super.setLength(length);
|
||||
super.setClipped(false);
|
||||
resetForeRadius();
|
||||
|
||||
super.setAftRadiusAutomatic(false);
|
||||
super.setAftRadius(radius);
|
||||
@ -46,86 +41,227 @@ public class NoseCone extends Transition implements InsideColorComponent {
|
||||
super.displayOrder_side = 1; // Order for displaying the component in the 2D side view
|
||||
super.displayOrder_back = 0; // Order for displaying the component in the 2D back view
|
||||
}
|
||||
|
||||
|
||||
/********** Get/set methods for component parameters **********/
|
||||
|
||||
@Override
|
||||
public double getForeRadius() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setForeRadius(double r) {
|
||||
// No-op
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isForeRadiusAutomatic() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setForeRadiusAutomatic(boolean b) {
|
||||
// No-op
|
||||
|
||||
/********** Nose cone dimensions **********/
|
||||
|
||||
/**
|
||||
* Returns the base radius of the nose cone (independent of whether the nose cone is flipped or not).
|
||||
* This method should be used over {@link #getAftRadius()} because it works for both normal and flipped nose cones.
|
||||
*/
|
||||
public double getBaseRadius() {
|
||||
return isFlipped ? getForeRadius() : getAftRadius();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean usesPreviousCompAutomatic() {
|
||||
return false;
|
||||
/**
|
||||
* Returns the raw base radius of the nose cone (independent of whether the nose cone is flipped or not).
|
||||
* This method should be used over {@link #getAftRadiusNoAutomatic()} because it works for both normal and flipped nose cones.
|
||||
*/
|
||||
public double getBaseRadiusNoAutomatic() {
|
||||
return isFlipped ? getForeRadiusNoAutomatic() : getAftRadiusNoAutomatic();
|
||||
}
|
||||
|
||||
@Override
|
||||
public double getForeShoulderLength() {
|
||||
return 0;
|
||||
/**
|
||||
* Sets the base radius of the nose cone (independent of whether the nose cone is flipped or not).
|
||||
* This method should be used over {@link #setAftRadius(double)} because it works for both normal and flipped nose cones.
|
||||
*/
|
||||
public void setBaseRadius(double radius) {
|
||||
if (isFlipped) {
|
||||
setForeRadius(radius);
|
||||
} else {
|
||||
setAftRadius(radius);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public double getForeShoulderRadius() {
|
||||
return 0;
|
||||
|
||||
/**
|
||||
* Returns whether the base radius of the nose cone takes it settings from the previous/next component
|
||||
* (independent of whether the nose cone is flipped or not).
|
||||
* This method should be used over {@link #isAftRadiusAutomatic()} because it works for both normal and flipped nose cones.
|
||||
*/
|
||||
public boolean isBaseRadiusAutomatic() {
|
||||
return isFlipped ? isForeRadiusAutomatic() : isAftRadiusAutomatic();
|
||||
}
|
||||
|
||||
@Override
|
||||
public double getForeShoulderThickness() {
|
||||
return 0;
|
||||
|
||||
/**
|
||||
* Sets whether the base radius of the nose cone takes it settings from the previous/next component
|
||||
* (independent of whether the nose cone is flipped or not).
|
||||
* This method should be used over {@link #setAftRadiusAutomatic(boolean)} because it works for both normal and flipped nose cones.
|
||||
*/
|
||||
public void setBaseRadiusAutomatic(boolean auto) {
|
||||
if (isFlipped) {
|
||||
setForeRadiusAutomatic(auto);
|
||||
} else {
|
||||
setAftRadiusAutomatic(auto);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isForeShoulderCapped() {
|
||||
return false;
|
||||
|
||||
/**
|
||||
* Returns the shoulder length, regardless of how the nose cone is flipped (independent of whether the nose cone is flipped or not).
|
||||
* This method should be used over {@link #getAftShoulderLength()} because it works for both normal and flipped nose cones.
|
||||
*/
|
||||
public double getShoulderLength() {
|
||||
return isFlipped ? getForeShoulderLength() : getAftShoulderLength();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setForeShoulderCapped(boolean capped) {
|
||||
// No-op
|
||||
|
||||
/**
|
||||
* Sets the shoulder length (independent of whether the nose cone is flipped or not).
|
||||
* This method should be used over {@link #setAftShoulderLength(double)} because it works for both normal and flipped nose cones.
|
||||
*/
|
||||
public void setShoulderLength(double length) {
|
||||
if (isFlipped) {
|
||||
setForeShoulderLength(length);
|
||||
} else {
|
||||
setAftShoulderLength(length);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setForeShoulderLength(double foreShoulderLength) {
|
||||
// No-op
|
||||
|
||||
/**
|
||||
* Returns the shoulder radius (independent of whether the nose cone is flipped or not).
|
||||
* This method should be used over {@link #getAftShoulderRadius()} because it works for both normal and flipped nose cones.
|
||||
*/
|
||||
public double getShoulderRadius() {
|
||||
return isFlipped ? getForeShoulderRadius() : getAftShoulderRadius();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setForeShoulderRadius(double foreShoulderRadius) {
|
||||
// No-op
|
||||
|
||||
/**
|
||||
* Sets the shoulder radius (independent of whether the nose cone is flipped or not).
|
||||
* This method should be used over {@link #setAftShoulderRadius(double)} because it works for both normal and flipped nose cones.
|
||||
*/
|
||||
public void setShoulderRadius(double radius) {
|
||||
if (isFlipped) {
|
||||
setForeShoulderRadius(radius);
|
||||
} else {
|
||||
setAftShoulderRadius(radius);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setForeShoulderThickness(double foreShoulderThickness) {
|
||||
// No-op
|
||||
|
||||
/**
|
||||
* Returns the shoulder thickness (independent of whether the nose cone is flipped or not).
|
||||
* This method should be used over {@link #getAftShoulderThickness()} because it works for both normal and flipped nose cones.
|
||||
*/
|
||||
public double getShoulderThickness() {
|
||||
return isFlipped ? getForeShoulderThickness() : getAftShoulderThickness();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Sets the shoulder thickness (independent of whether the nose cone is flipped or not).
|
||||
* This method should be used over {@link #setAftShoulderRadius(double)} because it works for both normal and flipped nose cones.
|
||||
*/
|
||||
public void setShoulderThickness(double thickness) {
|
||||
if (isFlipped) {
|
||||
setForeShoulderThickness(thickness);
|
||||
} else {
|
||||
setAftShoulderThickness(thickness);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the shoulder cap (independent of whether the nose cone is flipped or not).
|
||||
* This method should be used over {@link #isAftShoulderCapped()} because it works for both normal and flipped nose cones.
|
||||
*/
|
||||
public boolean isShoulderCapped() {
|
||||
return isFlipped ? isForeShoulderCapped() : isAftShoulderCapped();
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the shoulder cap (independent of whether the nose cone is flipped or not).
|
||||
* This method should be used over {@link #setAftShoulderCapped(boolean)} because it works for both normal and flipped nose cones.
|
||||
*/
|
||||
public void setShoulderCapped(boolean capped) {
|
||||
if (isFlipped) {
|
||||
setForeShoulderCapped(capped);
|
||||
} else {
|
||||
setAftShoulderCapped(capped);
|
||||
}
|
||||
}
|
||||
|
||||
/********** Other **********/
|
||||
|
||||
/**
|
||||
* Return true if the nose cone is flipped, i.e. converted to a tail cone, false if it is a regular nose cone.
|
||||
*/
|
||||
public boolean isFlipped() {
|
||||
return isFlipped;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the nose cone to be flipped, i.e. converted to a tail cone, or set it to be a regular nose cone.
|
||||
* @param flipped if true, the nose cone is converted to a tail cone, if false it is a regular nose cone.
|
||||
* @param sanityCheck whether to check if the auto radius parameter can be used for the new nose cone orientation
|
||||
*/
|
||||
public void setFlipped(boolean flipped, boolean sanityCheck) {
|
||||
for (RocketComponent listener : configListeners) {
|
||||
if (listener instanceof NoseCone) {
|
||||
((NoseCone) listener).setFlipped(flipped, sanityCheck);
|
||||
}
|
||||
}
|
||||
|
||||
if (isFlipped == flipped) {
|
||||
return;
|
||||
}
|
||||
|
||||
boolean previousByPass = isBypassComponentChangeEvent();
|
||||
setBypassChangeEvent(true);
|
||||
if (flipped) {
|
||||
setForeRadius(getAftRadiusNoAutomatic());
|
||||
setForeRadiusAutomatic(isAftRadiusAutomatic(), sanityCheck);
|
||||
setForeShoulderLength(getAftShoulderLength());
|
||||
setForeShoulderRadius(getAftShoulderRadius());
|
||||
setForeShoulderThickness(getAftShoulderThickness());
|
||||
setForeShoulderCapped(isAftShoulderCapped());
|
||||
|
||||
resetAftRadius();
|
||||
} else {
|
||||
setAftRadius(getForeRadiusNoAutomatic());
|
||||
setAftRadiusAutomatic(isForeRadiusAutomatic(), sanityCheck);
|
||||
setAftShoulderLength(getForeShoulderLength());
|
||||
setAftShoulderRadius(getForeShoulderRadius());
|
||||
setAftShoulderThickness(getForeShoulderThickness());
|
||||
setAftShoulderCapped(isForeShoulderCapped());
|
||||
|
||||
resetForeRadius();
|
||||
}
|
||||
setBypassChangeEvent(previousByPass);
|
||||
|
||||
isFlipped = flipped;
|
||||
fireComponentChangeEvent(ComponentChangeEvent.BOTH_CHANGE);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the nose cone to be flipped, i.e. converted to a tail cone, or set it to be a regular nose cone.
|
||||
* @param flipped if true, the nose cone is converted to a tail cone, if false it is a regular nose cone.
|
||||
*/
|
||||
public void setFlipped(boolean flipped) {
|
||||
setFlipped(flipped, true);
|
||||
}
|
||||
|
||||
private void resetForeRadius() {
|
||||
setForeRadius(0);
|
||||
setForeRadiusAutomatic(false);
|
||||
setForeShoulderLength(0);
|
||||
setForeShoulderRadius(0);
|
||||
setForeShoulderThickness(0);
|
||||
setForeShoulderCapped(false);
|
||||
}
|
||||
|
||||
private void resetAftRadius() {
|
||||
setAftRadius(0);
|
||||
setAftRadiusAutomatic(false);
|
||||
setAftShoulderLength(0);
|
||||
setAftShoulderRadius(0);
|
||||
setAftShoulderThickness(0);
|
||||
setAftShoulderCapped(false);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isClipped() {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void setClipped(boolean b) {
|
||||
// No-op
|
||||
}
|
||||
|
||||
|
||||
|
||||
/********** RocketComponent methods **********/
|
||||
|
||||
@ -136,9 +272,12 @@ public class NoseCone extends Transition implements InsideColorComponent {
|
||||
|
||||
@Override
|
||||
protected void loadFromPreset(ComponentPreset preset) {
|
||||
|
||||
// We first need to unflip, because the preset loading always applies settings for a normal nose cone (e.g. aft diameter)
|
||||
boolean flipped = isFlipped;
|
||||
setFlipped(false);
|
||||
//Many parameters are handled by the super class Transition.loadFromPreset
|
||||
super.loadFromPreset(preset);
|
||||
setFlipped(flipped);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@ -207,12 +207,6 @@ public class RailButton extends ExternalComponent implements AnglePositionable,
|
||||
clearPreset();
|
||||
fireComponentChangeEvent(ComponentChangeEvent.BOTH_CHANGE);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isAerodynamic(){
|
||||
// TODO: implement aerodynamics
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public double getAngleOffset(){
|
||||
|
||||
@ -177,6 +177,7 @@ public abstract class RecoveryDevice extends MassObject implements FlightConfigu
|
||||
@Override
|
||||
public void clearConfigListeners() {
|
||||
super.clearConfigListeners();
|
||||
// The DeploymentConfiguration also has listeners, so clear them as well
|
||||
DeploymentConfiguration thisConfig = getDeploymentConfigurations().getDefault();
|
||||
thisConfig.clearConfigListeners();
|
||||
}
|
||||
|
||||
@ -406,37 +406,37 @@ public class Rocket extends ComponentAssembly {
|
||||
* and therefore fires an UNDO_EVENT, masked with all applicable mass/aerodynamic/tree
|
||||
* changes.
|
||||
*/
|
||||
public void loadFrom(Rocket r) {
|
||||
public void loadFrom(Rocket source) {
|
||||
|
||||
// Store list of components to invalidate after event has been fired
|
||||
List<RocketComponent> toInvalidate = this.copyFrom(r);
|
||||
List<RocketComponent> toInvalidate = this.copyFrom(source);
|
||||
|
||||
int type = ComponentChangeEvent.UNDO_CHANGE | ComponentChangeEvent.NONFUNCTIONAL_CHANGE;
|
||||
if (this.massModID != r.massModID)
|
||||
if (this.massModID != source.massModID)
|
||||
type |= ComponentChangeEvent.MASS_CHANGE;
|
||||
if (this.aeroModID != r.aeroModID)
|
||||
if (this.aeroModID != source.aeroModID)
|
||||
type |= ComponentChangeEvent.AERODYNAMIC_CHANGE;
|
||||
// Loading a rocket is always a tree change since the component objects change
|
||||
type |= ComponentChangeEvent.TREE_CHANGE;
|
||||
|
||||
this.modID = r.modID;
|
||||
this.massModID = r.massModID;
|
||||
this.aeroModID = r.aeroModID;
|
||||
this.treeModID = r.treeModID;
|
||||
this.functionalModID = r.functionalModID;
|
||||
this.refType = r.refType;
|
||||
this.customReferenceLength = r.customReferenceLength;
|
||||
this.stageMap = r.stageMap;
|
||||
this.modID = source.modID;
|
||||
this.massModID = source.massModID;
|
||||
this.aeroModID = source.aeroModID;
|
||||
this.treeModID = source.treeModID;
|
||||
this.functionalModID = source.functionalModID;
|
||||
this.refType = source.refType;
|
||||
this.customReferenceLength = source.customReferenceLength;
|
||||
this.stageMap = source.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()) {
|
||||
for (FlightConfigurationId key : source.configSet.map.keySet()) {
|
||||
this.configSet.set(key, new FlightConfiguration(this, key));
|
||||
}
|
||||
this.selectedConfiguration = this.configSet.get(r.getSelectedConfiguration().getId());
|
||||
this.selectedConfiguration = this.configSet.get(source.getSelectedConfiguration().getId());
|
||||
|
||||
this.perfectFinish = r.perfectFinish;
|
||||
this.perfectFinish = source.perfectFinish;
|
||||
|
||||
this.checkComponentStructure();
|
||||
|
||||
@ -453,25 +453,6 @@ public class Rocket extends ComponentAssembly {
|
||||
|
||||
/////// Implement the ComponentChangeListener lists
|
||||
|
||||
/**
|
||||
* Creates a new EventListenerList for this component. This is necessary when cloning
|
||||
* the structure.
|
||||
*/
|
||||
public void resetListeners() {
|
||||
// System.out.println("RESETTING LISTENER LIST of Rocket "+this);
|
||||
listenerList = new HashSet<EventListener>();
|
||||
}
|
||||
|
||||
|
||||
public void printListeners() {
|
||||
System.out.println("" + this + " has " + listenerList.size() + " listeners:");
|
||||
int i = 0;
|
||||
for (EventListener l : listenerList) {
|
||||
System.out.println(" " + (i) + ": " + l);
|
||||
i++;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addComponentChangeListener(ComponentChangeListener l) {
|
||||
checkState();
|
||||
@ -497,10 +478,6 @@ public class Rocket extends ComponentAssembly {
|
||||
try {
|
||||
checkState();
|
||||
|
||||
{ // vvvv DEVEL vvvv
|
||||
//System.err.println("fireEvent@rocket.");
|
||||
} // ^^^^ DEVEL ^^^^
|
||||
|
||||
// Update modification ID's only for normal (not undo/redo) events
|
||||
if (!cce.isUndoChange()) {
|
||||
modID = UniqueID.next();
|
||||
|
||||
@ -448,6 +448,7 @@ public abstract class RocketComponent implements ChangeSource, Cloneable, Iterab
|
||||
}
|
||||
// Make sure the config listeners aren't cloned
|
||||
clone.configListeners = new LinkedList<>();
|
||||
clone.bypassComponentChangeEvent = false;
|
||||
return clone;
|
||||
}
|
||||
|
||||
@ -603,7 +604,7 @@ public abstract class RocketComponent implements ChangeSource, Cloneable, Iterab
|
||||
for (RocketComponent listener : configListeners) {
|
||||
listener.setBypassChangeEvent(false);
|
||||
listener.setMassOverridden(o);
|
||||
listener.setBypassChangeEvent(false);
|
||||
listener.setBypassChangeEvent(true);
|
||||
}
|
||||
|
||||
if (massOverridden == o) {
|
||||
@ -2277,7 +2278,11 @@ public abstract class RocketComponent implements ChangeSource, Cloneable, Iterab
|
||||
this.bypassComponentChangeEvent = newValue;
|
||||
}
|
||||
|
||||
public boolean getBypassComponentChangeEvent() {
|
||||
/**
|
||||
* Returns whether the current component if ignoring ComponentChangeEvents.
|
||||
* @return true if the component is ignoring ComponentChangeEvents.
|
||||
*/
|
||||
public boolean isBypassComponentChangeEvent() {
|
||||
return this.bypassComponentChangeEvent;
|
||||
}
|
||||
|
||||
@ -2287,7 +2292,18 @@ public abstract class RocketComponent implements ChangeSource, Cloneable, Iterab
|
||||
* @return true if listener was successfully added, false if not
|
||||
*/
|
||||
public boolean addConfigListener(RocketComponent listener) {
|
||||
if (listener == null || configListeners.contains(listener) || listener == this) {
|
||||
if (isBypassComponentChangeEvent()) {
|
||||
// This is a precaution. If you are multi-comp editing and the current component is bypassing events,
|
||||
// the editing will be REALLY weird, see GitHub issue #1956.
|
||||
throw new IllegalStateException("Cannot add config listener while bypassing events");
|
||||
}
|
||||
if (listener == null) {
|
||||
return false;
|
||||
}
|
||||
if (listener.getConfigListeners().size() > 0) {
|
||||
throw new IllegalArgumentException("Listener already has config listeners");
|
||||
}
|
||||
if (configListeners.contains(listener) || listener == this) {
|
||||
return false;
|
||||
}
|
||||
configListeners.add(listener);
|
||||
@ -2555,6 +2571,7 @@ public abstract class RocketComponent implements ChangeSource, Cloneable, Iterab
|
||||
this.displayOrder_side = src.displayOrder_side;
|
||||
this.displayOrder_back = src.displayOrder_back;
|
||||
this.configListeners = new LinkedList<>();
|
||||
this.bypassComponentChangeEvent = false;
|
||||
if (this instanceof InsideColorComponent && src instanceof InsideColorComponent) {
|
||||
InsideColorComponentHandler icch = new InsideColorComponentHandler(this);
|
||||
icch.copyFrom(((InsideColorComponent) src).getInsideColorComponentHandler());
|
||||
|
||||
@ -10,7 +10,7 @@ import net.sf.openrocket.preset.ComponentPreset;
|
||||
import net.sf.openrocket.util.BoundingBox;
|
||||
import net.sf.openrocket.util.Coordinate;
|
||||
import net.sf.openrocket.util.MathUtil;
|
||||
|
||||
import net.sf.openrocket.rocketcomponent.position.RadiusMethod;
|
||||
|
||||
/**
|
||||
* Class for an axially symmetric rocket component generated by rotating
|
||||
@ -621,7 +621,11 @@ public abstract class SymmetricComponent extends BodyComponent implements BoxBou
|
||||
while (0 <= searchSiblingIndex) {
|
||||
final RocketComponent searchSibling = searchParent.getChild(searchSiblingIndex);
|
||||
if (searchSibling instanceof SymmetricComponent) {
|
||||
return (SymmetricComponent) searchSibling;
|
||||
SymmetricComponent candidate = (SymmetricComponent) searchSibling;
|
||||
if (inline(candidate)) {
|
||||
return candidate;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
--searchSiblingIndex;
|
||||
}
|
||||
@ -658,9 +662,12 @@ public abstract class SymmetricComponent extends BodyComponent implements BoxBou
|
||||
if(searchParent instanceof ComponentAssembly){
|
||||
while (searchSiblingIndex < searchParent.getChildCount()) {
|
||||
final RocketComponent searchSibling = searchParent.getChild(searchSiblingIndex);
|
||||
|
||||
if (searchSibling instanceof SymmetricComponent) {
|
||||
return (SymmetricComponent) searchSibling;
|
||||
SymmetricComponent candidate = (SymmetricComponent) searchSibling;
|
||||
if (inline(candidate)) {
|
||||
return candidate;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
++searchSiblingIndex;
|
||||
}
|
||||
@ -671,6 +678,29 @@ public abstract class SymmetricComponent extends BodyComponent implements BoxBou
|
||||
return null;
|
||||
}
|
||||
|
||||
/***
|
||||
* Determine whether a candidate symmetric component is in line with us
|
||||
*
|
||||
*/
|
||||
private boolean inline(final SymmetricComponent candidate) {
|
||||
// if we share a parent, we are in line
|
||||
if (this.parent == candidate.parent)
|
||||
return true;
|
||||
|
||||
// if both of our parents are either not ring instanceable, or
|
||||
// have a radial offset of 0 from their centerline, we are in line.
|
||||
|
||||
if ((this.parent instanceof RingInstanceable) &&
|
||||
(!MathUtil.equals(this.parent.getRadiusMethod().getRadius(this.parent.parent, this, this.parent.getRadiusOffset()), 0)))
|
||||
return false;
|
||||
|
||||
if ((candidate.parent instanceof RingInstanceable) &&
|
||||
(!MathUtil.equals(candidate.parent.getRadiusMethod().getRadius(candidate.parent.parent, candidate, candidate.parent.getRadiusOffset()), 0)))
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks whether the component uses the previous symmetric component for its auto diameter.
|
||||
*/
|
||||
|
||||
@ -5,17 +5,13 @@ import static net.sf.openrocket.util.MathUtil.pow2;
|
||||
import static net.sf.openrocket.util.MathUtil.pow3;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.EventObject;
|
||||
|
||||
import net.sf.openrocket.appearance.Appearance;
|
||||
import net.sf.openrocket.appearance.Decal;
|
||||
import net.sf.openrocket.l10n.Translator;
|
||||
import net.sf.openrocket.preset.ComponentPreset;
|
||||
import net.sf.openrocket.preset.ComponentPreset.Type;
|
||||
import net.sf.openrocket.startup.Application;
|
||||
import net.sf.openrocket.util.Coordinate;
|
||||
import net.sf.openrocket.util.MathUtil;
|
||||
import net.sf.openrocket.util.StateChangeListener;
|
||||
|
||||
|
||||
public class Transition extends SymmetricComponent implements InsideColorComponent {
|
||||
@ -27,8 +23,8 @@ public class Transition extends SymmetricComponent implements InsideColorCompone
|
||||
private double shapeParameter;
|
||||
private boolean clipped; // Not to be read - use isClipped(), which may be overridden
|
||||
|
||||
private double foreRadius, aftRadius;
|
||||
private boolean autoForeRadius, autoAftRadius2; // Whether the start radius is automatic
|
||||
protected double foreRadius, aftRadius; // Warning: avoid using these directly, use getForeRadius() and getAftRadius() instead (because the definition of the two can change for flipped nose cones)
|
||||
protected boolean autoForeRadius, autoAftRadius; // Whether the start radius is automatic
|
||||
|
||||
|
||||
private double foreShoulderRadius;
|
||||
@ -53,7 +49,7 @@ public class Transition extends SymmetricComponent implements InsideColorCompone
|
||||
this.aftRadius = DEFAULT_RADIUS;
|
||||
this.length = DEFAULT_RADIUS * 3;
|
||||
this.autoForeRadius = true;
|
||||
this.autoAftRadius2 = true;
|
||||
this.autoAftRadius = true;
|
||||
|
||||
this.type = Shape.CONICAL;
|
||||
this.shapeParameter = 0;
|
||||
@ -81,19 +77,24 @@ public class Transition extends SymmetricComponent implements InsideColorCompone
|
||||
@Override
|
||||
public double getForeRadius() {
|
||||
if (isForeRadiusAutomatic()) {
|
||||
// Get the automatic radius from the front
|
||||
double r = -1;
|
||||
SymmetricComponent c = this.getPreviousSymmetricComponent();
|
||||
if (c != null) {
|
||||
r = c.getFrontAutoRadius();
|
||||
}
|
||||
if (r < 0)
|
||||
r = DEFAULT_RADIUS;
|
||||
return r;
|
||||
return getAutoForeRadius();
|
||||
}
|
||||
return foreRadius;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the automatic radius from the front, taken from the previous component. Returns the default radius if there
|
||||
* is no previous component.
|
||||
*/
|
||||
protected double getAutoForeRadius() {
|
||||
SymmetricComponent c = this.getPreviousSymmetricComponent();
|
||||
if (c != null) {
|
||||
return c.getFrontAutoRadius();
|
||||
} else {
|
||||
return DEFAULT_RADIUS;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the fore radius that was manually entered, so not the value that the component received from automatic
|
||||
* fore radius.
|
||||
@ -136,13 +137,24 @@ public class Transition extends SymmetricComponent implements InsideColorCompone
|
||||
return autoForeRadius;
|
||||
}
|
||||
|
||||
public void setForeRadiusAutomatic(boolean auto) {
|
||||
/**
|
||||
* Set the fore radius to automatic mode (takes its value from the previous symmetric component's radius).
|
||||
*
|
||||
* @param auto whether to set the fore radius to automatic mode
|
||||
* @param sanityCheck whether to sanity check auto mode for whether there is a previous component of which you can take the radius
|
||||
*/
|
||||
public void setForeRadiusAutomatic(boolean auto, boolean sanityCheck) {
|
||||
for (RocketComponent listener : configListeners) {
|
||||
if (listener instanceof Transition) {
|
||||
((Transition) listener).setForeRadiusAutomatic(auto);
|
||||
}
|
||||
}
|
||||
|
||||
// You can only set the auto fore radius if it is possible
|
||||
if (sanityCheck) {
|
||||
auto = auto && canUsePreviousCompAutomatic();
|
||||
}
|
||||
|
||||
if (autoForeRadius == auto)
|
||||
return;
|
||||
|
||||
@ -152,25 +164,34 @@ public class Transition extends SymmetricComponent implements InsideColorCompone
|
||||
fireComponentChangeEvent(ComponentChangeEvent.BOTH_CHANGE);
|
||||
}
|
||||
|
||||
public void setForeRadiusAutomatic(boolean auto) {
|
||||
setForeRadiusAutomatic(auto, false);
|
||||
}
|
||||
|
||||
|
||||
//////// Aft radius /////////
|
||||
|
||||
@Override
|
||||
public double getAftRadius() {
|
||||
if (isAftRadiusAutomatic()) {
|
||||
// Return the auto radius from the rear
|
||||
double r = -1;
|
||||
SymmetricComponent c = this.getNextSymmetricComponent();
|
||||
if (c != null) {
|
||||
r = c.getRearAutoRadius();
|
||||
}
|
||||
if (r < 0)
|
||||
r = DEFAULT_RADIUS;
|
||||
return r;
|
||||
return getAutoAftRadius();
|
||||
}
|
||||
return aftRadius;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the automatic radius from the rear, taken from the next component. Returns the default radius if there
|
||||
* is no next component.
|
||||
*/
|
||||
protected double getAutoAftRadius() {
|
||||
SymmetricComponent c = this.getNextSymmetricComponent();
|
||||
if (c != null) {
|
||||
return c.getRearAutoRadius();
|
||||
} else {
|
||||
return DEFAULT_RADIUS;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the aft radius that was manually entered, so not the value that the component received from automatic
|
||||
* zft radius.
|
||||
@ -191,10 +212,10 @@ public class Transition extends SymmetricComponent implements InsideColorCompone
|
||||
}
|
||||
}
|
||||
|
||||
if ((this.aftRadius == radius) && (autoAftRadius2 == false))
|
||||
if ((this.aftRadius == radius) && (autoAftRadius == false))
|
||||
return;
|
||||
|
||||
this.autoAftRadius2 = false;
|
||||
this.autoAftRadius = false;
|
||||
this.aftRadius = Math.max(radius, 0);
|
||||
|
||||
if (doClamping && this.thickness > this.foreRadius && this.thickness > this.aftRadius)
|
||||
@ -210,25 +231,40 @@ public class Transition extends SymmetricComponent implements InsideColorCompone
|
||||
|
||||
@Override
|
||||
public boolean isAftRadiusAutomatic() {
|
||||
return autoAftRadius2;
|
||||
return autoAftRadius;
|
||||
}
|
||||
|
||||
public void setAftRadiusAutomatic(boolean auto) {
|
||||
/**
|
||||
* Set the aft radius to automatic mode (takes its value from the next symmetric component's radius).
|
||||
*
|
||||
* @param auto whether to set the aft radius to automatic mode
|
||||
* @param sanityCheck whether to sanity check auto mode for whether there is a next component of which you can take the radius
|
||||
*/
|
||||
public void setAftRadiusAutomatic(boolean auto, boolean sanityCheck) {
|
||||
for (RocketComponent listener : configListeners) {
|
||||
if (listener instanceof Transition) {
|
||||
((Transition) listener).setAftRadiusAutomatic(auto);
|
||||
}
|
||||
}
|
||||
|
||||
if (autoAftRadius2 == auto)
|
||||
// You can only set the auto aft radius if it is possible
|
||||
if (sanityCheck) {
|
||||
auto = auto && canUseNextCompAutomatic();
|
||||
}
|
||||
|
||||
if (autoAftRadius == auto)
|
||||
return;
|
||||
|
||||
autoAftRadius2 = auto;
|
||||
autoAftRadius = auto;
|
||||
|
||||
clearPreset();
|
||||
fireComponentChangeEvent(ComponentChangeEvent.BOTH_CHANGE);
|
||||
}
|
||||
|
||||
public void setAftRadiusAutomatic(boolean auto) {
|
||||
setAftRadiusAutomatic(auto, false);
|
||||
}
|
||||
|
||||
|
||||
//// Radius automatics
|
||||
|
||||
@ -257,6 +293,32 @@ public class Transition extends SymmetricComponent implements InsideColorCompone
|
||||
return isAftRadiusAutomatic();
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks whether this component can use the automatic radius of the previous symmetric component.
|
||||
* @return false if there is no previous symmetric component, or if the previous component already has this component
|
||||
* as its auto dimension reference
|
||||
*/
|
||||
public boolean canUsePreviousCompAutomatic() {
|
||||
SymmetricComponent referenceComp = getPreviousSymmetricComponent();
|
||||
if (referenceComp == null) {
|
||||
return false;
|
||||
}
|
||||
return !referenceComp.usesNextCompAutomatic();
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks whether this component can use the automatic radius of the next symmetric component.
|
||||
* @return false if there is no next symmetric component, or if the next component already has this component
|
||||
* as its auto dimension reference
|
||||
*/
|
||||
public boolean canUseNextCompAutomatic() {
|
||||
SymmetricComponent referenceComp = getNextSymmetricComponent();
|
||||
if (referenceComp == null) {
|
||||
return false;
|
||||
}
|
||||
return !referenceComp.usesPreviousCompAutomatic();
|
||||
}
|
||||
|
||||
|
||||
//////// Type & shape /////////
|
||||
|
||||
|
||||
@ -7,7 +7,9 @@ import java.util.Deque;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import net.sf.openrocket.aerodynamics.FlightConditions;
|
||||
import net.sf.openrocket.aerodynamics.Warning;
|
||||
import net.sf.openrocket.aerodynamics.WarningSet;
|
||||
import net.sf.openrocket.l10n.Translator;
|
||||
import net.sf.openrocket.motor.IgnitionEvent;
|
||||
import net.sf.openrocket.motor.MotorConfiguration;
|
||||
@ -58,12 +60,14 @@ public class BasicEventSimulationEngine implements SimulationEngine {
|
||||
|
||||
// this is just a list of simulation branches to
|
||||
Deque<SimulationStatus> toSimulate = new ArrayDeque<SimulationStatus>();
|
||||
|
||||
FlightData flightData;
|
||||
|
||||
@Override
|
||||
public FlightData simulate(SimulationConditions simulationConditions) throws SimulationException {
|
||||
|
||||
// Set up flight data
|
||||
FlightData flightData = new FlightData();
|
||||
flightData = new FlightData();
|
||||
|
||||
// Set up rocket configuration
|
||||
this.fcid = simulationConditions.getFlightConfigurationID();
|
||||
@ -82,6 +86,13 @@ public class BasicEventSimulationEngine implements SimulationEngine {
|
||||
throw new MotorIgnitionException(trans.get("BasicEventSimulationEngine.error.noMotorsDefined"));
|
||||
}
|
||||
|
||||
// Can't calculate stability
|
||||
if (currentStatus.getSimulationConditions().getAerodynamicCalculator()
|
||||
.getCP(currentStatus.getConfiguration(),
|
||||
new FlightConditions(currentStatus.getConfiguration()),
|
||||
new WarningSet()).weight < MathUtil.EPSILON)
|
||||
throw new SimulationException(trans.get("BasicEventSimulationEngine.error.cantCalculateStability"));
|
||||
|
||||
// Problems that let us simulate, but result is likely bad
|
||||
|
||||
// No recovery device
|
||||
@ -268,6 +279,11 @@ public class BasicEventSimulationEngine implements SimulationEngine {
|
||||
|
||||
// Add FlightEvent for Abort.
|
||||
currentStatus.getFlightData().addEvent(new FlightEvent(FlightEvent.Type.EXCEPTION, currentStatus.getSimulationTime(), currentStatus.getConfiguration().getRocket(), e.getLocalizedMessage()));
|
||||
|
||||
flightData.addBranch(currentStatus.getFlightData());
|
||||
flightData.getWarningSet().addAll(currentStatus.getWarnings());
|
||||
|
||||
e.setFlightData(flightData);
|
||||
|
||||
throw e;
|
||||
}
|
||||
@ -380,7 +396,13 @@ public class BasicEventSimulationEngine implements SimulationEngine {
|
||||
|
||||
case IGNITION: {
|
||||
MotorClusterState motorState = (MotorClusterState) event.getData();
|
||||
|
||||
|
||||
// If there are multiple ignition events (as is the case if the preceding stage has several burnout events, for instance)
|
||||
// We get multiple ignition events for the upper stage motor. Ignore are all after the first.
|
||||
if (motorState.getIgnitionTime() < currentStatus.getSimulationTime()) {
|
||||
log.info("Ignoring motor " +motorState.toDescription()+" ignition event @"+currentStatus.getSimulationTime());
|
||||
continue;
|
||||
}
|
||||
log.info(" Igniting motor: "+motorState.toDescription()+" @"+currentStatus.getSimulationTime());
|
||||
motorState.ignite( event.getTime());
|
||||
|
||||
|
||||
@ -1,6 +1,7 @@
|
||||
package net.sf.openrocket.simulation;
|
||||
|
||||
import net.sf.openrocket.models.atmosphere.AtmosphericConditions;
|
||||
import net.sf.openrocket.rocketcomponent.InstanceMap;
|
||||
import net.sf.openrocket.rocketcomponent.RecoveryDevice;
|
||||
import net.sf.openrocket.simulation.exception.SimulationException;
|
||||
import net.sf.openrocket.util.Coordinate;
|
||||
@ -35,8 +36,10 @@ public class BasicLandingStepper extends AbstractSimulationStepper {
|
||||
|
||||
// Get total CD
|
||||
double mach = airSpeed.length() / atmosphere.getMachSpeed();
|
||||
|
||||
final InstanceMap imap = status.getConfiguration().getActiveInstances();
|
||||
for (RecoveryDevice c : status.getDeployedRecoveryDevices()) {
|
||||
totalCD += c.getCD(mach) * c.getArea() / refArea;
|
||||
totalCD += imap.count(c) * c.getCD(mach) * c.getArea() / refArea;
|
||||
}
|
||||
|
||||
// Compute drag force
|
||||
|
||||
@ -69,6 +69,27 @@ public class BasicTumbleStepper extends AbstractSimulationStepper {
|
||||
double timeStep = MathUtil.min(0.5 / linearAcceleration.length(), RECOVERY_TIME_STEP);
|
||||
|
||||
// Perform Euler integration
|
||||
Coordinate newPosition = status.getRocketPosition().add(status.getRocketVelocity().multiply(timeStep)).
|
||||
add(linearAcceleration.multiply(MathUtil.pow2(timeStep) / 2));
|
||||
|
||||
// If I've hit the ground, recalculate time step and position
|
||||
if (newPosition.z < 0) {
|
||||
|
||||
final double a = linearAcceleration.z;
|
||||
final double v = status.getRocketVelocity().z;
|
||||
final double z0 = status.getRocketPosition().z;
|
||||
|
||||
// The new timestep is the solution of
|
||||
// 1/2 at^2 + vt + z0 = 0
|
||||
timeStep = (-v - Math.sqrt(v*v - 2*a*z0))/a;
|
||||
|
||||
newPosition = status.getRocketPosition().add(status.getRocketVelocity().multiply(timeStep)).
|
||||
add(linearAcceleration.multiply(MathUtil.pow2(timeStep) / 2));
|
||||
|
||||
// avoid rounding error in new altitude
|
||||
newPosition = newPosition.setZ(0);
|
||||
}
|
||||
|
||||
status.setRocketPosition(status.getRocketPosition().add(status.getRocketVelocity().multiply(timeStep)).
|
||||
add(linearAcceleration.multiply(MathUtil.pow2(timeStep) / 2)));
|
||||
status.setRocketVelocity(status.getRocketVelocity().add(linearAcceleration.multiply(timeStep)));
|
||||
|
||||
@ -1,7 +1,11 @@
|
||||
package net.sf.openrocket.simulation.exception;
|
||||
|
||||
import net.sf.openrocket.simulation.FlightData;
|
||||
|
||||
public class SimulationException extends Exception {
|
||||
|
||||
private FlightData flightData = null;
|
||||
|
||||
public SimulationException() {
|
||||
|
||||
}
|
||||
@ -18,4 +22,11 @@ public class SimulationException extends Exception {
|
||||
super(message, cause);
|
||||
}
|
||||
|
||||
public void setFlightData(FlightData f) {
|
||||
flightData = f;
|
||||
}
|
||||
|
||||
public FlightData getFlightData() {
|
||||
return flightData;
|
||||
}
|
||||
}
|
||||
|
||||
@ -76,6 +76,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";
|
||||
public static final String MARKER_STYLE_ICON = "MARKER_STYLE_ICON";
|
||||
private static final String SHOW_MARKERS = "SHOW_MARKERS";
|
||||
private static final String SHOW_ROCKSIM_FORMAT_WARNING = "SHOW_ROCKSIM_FORMAT_WARNING";
|
||||
|
||||
|
||||
@ -185,8 +185,8 @@ public class SerializeThrustcurveMotors {
|
||||
System.exit(1);
|
||||
} else {
|
||||
while (iterator.hasNext()) {
|
||||
Pair<String, InputStream> f = iterator.next();
|
||||
String fileName = f.getU();
|
||||
Pair<File, InputStream> f = iterator.next();
|
||||
String fileName = f.getU().getName();
|
||||
InputStream is = f.getV();
|
||||
|
||||
List<ThrustCurveMotor.Builder> motors = loader.load(is, fileName);
|
||||
|
||||
@ -90,8 +90,11 @@ public abstract class Unit {
|
||||
* @return A string representation of the number in these units.
|
||||
*/
|
||||
public String toString(double value) {
|
||||
double val = toUnit(value);
|
||||
if (Double.isNaN(value))
|
||||
return "N/A";
|
||||
|
||||
double val = toUnit(value);
|
||||
|
||||
if (Math.abs(val) > 1E6) {
|
||||
return expFormat.format(val);
|
||||
}
|
||||
|
||||
@ -82,7 +82,7 @@ public class LinearInterpolator implements Cloneable {
|
||||
|
||||
if ( y1 != null ) {
|
||||
// Wow, x was a key in the map. Such luck.
|
||||
return y1.doubleValue();
|
||||
return y1;
|
||||
}
|
||||
|
||||
// we now know that x is not in the map, so we need to find the lower and higher keys.
|
||||
@ -96,16 +96,16 @@ public class LinearInterpolator implements Cloneable {
|
||||
Double firstKey = sortMap.firstKey();
|
||||
|
||||
// x is smaller than the first entry in the map.
|
||||
if ( x < firstKey.doubleValue() ) {
|
||||
if ( x < firstKey) {
|
||||
y1 = sortMap.get(firstKey);
|
||||
return y1.doubleValue();
|
||||
return y1;
|
||||
}
|
||||
|
||||
// floor key is the largest key smaller than x - since we have at least one key,
|
||||
// and x>=firstKey, we know that floorKey != null.
|
||||
Double floorKey = sortMap.subMap(firstKey, x).lastKey();
|
||||
|
||||
x1 = floorKey.doubleValue();
|
||||
x1 = floorKey;
|
||||
y1 = sortMap.get(floorKey);
|
||||
|
||||
// Now we need to find the key that is greater or equal to x
|
||||
@ -113,16 +113,16 @@ public class LinearInterpolator implements Cloneable {
|
||||
|
||||
// Check if x is bigger than all the entries.
|
||||
if ( tailMap.isEmpty() ) {
|
||||
return y1.doubleValue();
|
||||
return y1;
|
||||
}
|
||||
Double ceilKey = tailMap.firstKey();
|
||||
|
||||
// Check if x is bigger than all the entries.
|
||||
if ( ceilKey == null ) {
|
||||
return y1.doubleValue();
|
||||
return y1;
|
||||
}
|
||||
|
||||
x2 = ceilKey.doubleValue();
|
||||
x2 = ceilKey;
|
||||
y2 = sortMap.get(ceilKey);
|
||||
|
||||
return (x - x1)/(x2-x1) * (y2-y1) + y1;
|
||||
|
||||
@ -290,7 +290,7 @@ public class BarrowmanCalculatorTest {
|
||||
FlightConfiguration configuration = rocket.getSelectedConfiguration();
|
||||
WarningSet warnings = new WarningSet();
|
||||
|
||||
calc.testIsContinuous(configuration, rocket, warnings);
|
||||
calc.checkGeometry(configuration, rocket, warnings);
|
||||
assertTrue("Estes Alpha III should be continuous: ", warnings.isEmpty());
|
||||
}
|
||||
|
||||
@ -301,7 +301,7 @@ public class BarrowmanCalculatorTest {
|
||||
FlightConfiguration configuration = rocket.getSelectedConfiguration();
|
||||
WarningSet warnings = new WarningSet();
|
||||
|
||||
calc.testIsContinuous(configuration, rocket, warnings);
|
||||
calc.checkGeometry(configuration, rocket, warnings);
|
||||
assertTrue("F9H should be continuous: ", warnings.isEmpty());
|
||||
}
|
||||
|
||||
@ -319,7 +319,7 @@ public class BarrowmanCalculatorTest {
|
||||
body.setOuterRadius( 0.012 );
|
||||
body.setName( body.getName()+" << discontinuous");
|
||||
|
||||
calc.testIsContinuous(configuration, rocket, warnings);
|
||||
calc.checkGeometry(configuration, rocket, warnings);
|
||||
assertFalse(" Estes Alpha III has an undetected discontinuity:", warnings.isEmpty());
|
||||
}
|
||||
|
||||
@ -340,7 +340,7 @@ public class BarrowmanCalculatorTest {
|
||||
body.setOuterRadius( 0.012 );
|
||||
body.setName( body.getName()+" << discontinuous");
|
||||
|
||||
calc.testIsContinuous(configuration, rocket, warnings);
|
||||
calc.checkGeometry(configuration, rocket, warnings);
|
||||
assertFalse(" Missed discontinuity in Falcon 9 Heavy:" , warnings.isEmpty());
|
||||
}
|
||||
|
||||
|
||||
101
core/test/net/sf/openrocket/aerodynamics/RailButtonCalcTest.java
Normal file
@ -0,0 +1,101 @@
|
||||
package net.sf.openrocket.aerodynamics;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import org.junit.BeforeClass;
|
||||
import org.junit.Test;
|
||||
|
||||
import com.google.inject.Guice;
|
||||
import com.google.inject.Injector;
|
||||
import com.google.inject.Module;
|
||||
|
||||
import net.sf.openrocket.ServicesForTesting;
|
||||
import net.sf.openrocket.aerodynamics.BarrowmanCalculator;
|
||||
import net.sf.openrocket.aerodynamics.barrowman.RailButtonCalc;
|
||||
import net.sf.openrocket.plugin.PluginModule;
|
||||
import net.sf.openrocket.rocketcomponent.FlightConfiguration;
|
||||
import net.sf.openrocket.rocketcomponent.BodyTube;
|
||||
import net.sf.openrocket.rocketcomponent.RailButton;
|
||||
import net.sf.openrocket.rocketcomponent.LaunchLug;
|
||||
import net.sf.openrocket.rocketcomponent.Rocket;
|
||||
import net.sf.openrocket.rocketcomponent.position.AxialMethod;
|
||||
import net.sf.openrocket.startup.Application;
|
||||
import net.sf.openrocket.util.MathUtil;
|
||||
import net.sf.openrocket.util.TestRockets;
|
||||
import net.sf.openrocket.util.Transformation;
|
||||
|
||||
public class RailButtonCalcTest {
|
||||
protected final double EPSILON = 0.0001;
|
||||
|
||||
private static Injector injector;
|
||||
@BeforeClass
|
||||
public static void setup() {
|
||||
Module applicationModule = new ServicesForTesting();
|
||||
Module pluginModule = new PluginModule();
|
||||
|
||||
injector = Guice.createInjector( applicationModule, pluginModule);
|
||||
Application.setInjector(injector);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testRailButtons() {
|
||||
|
||||
Rocket rocket = TestRockets.makeEstesAlphaIII();
|
||||
FlightConfiguration config = rocket.getSelectedConfiguration();
|
||||
|
||||
// Get the body tube...
|
||||
BodyTube tube = (BodyTube)rocket.getChild(0).getChild(1);
|
||||
|
||||
// Replace the launch lug with a (single) railbutton
|
||||
LaunchLug lug = (LaunchLug)tube.getChild(1);
|
||||
rocket.removeChild(lug);
|
||||
|
||||
RailButton button = new RailButton();
|
||||
tube.addChild(button);
|
||||
|
||||
// Button parameters from Binder Design standard 1010
|
||||
button.setOuterDiameter(0.011);
|
||||
button.setInnerDiameter(0.006);
|
||||
|
||||
button.setBaseHeight(0.002);
|
||||
button.setFlangeHeight(0.002);
|
||||
button.setTotalHeight(0.008);
|
||||
|
||||
button.setAxialMethod(AxialMethod.ABSOLUTE);
|
||||
button.setAxialOffset(1.0);
|
||||
|
||||
// Set up flight conditions
|
||||
FlightConditions conditions = new FlightConditions(config);
|
||||
conditions.setMach(1.0);
|
||||
|
||||
BarrowmanCalculator barrowmanObj = new BarrowmanCalculator();
|
||||
RailButtonCalc calcObj = new RailButtonCalc(button);
|
||||
|
||||
// Calculate effective CD for rail button
|
||||
// Boundary layer height
|
||||
double rex = calcObj.calculateReynoldsNumber(1.0, conditions); // Reynolds number of button location
|
||||
double del = 0.37 * 1.0 / Math.pow(rex, 0.2); // Boundary layer height
|
||||
|
||||
// Interpolate velocity at midpoint of railbutton
|
||||
double mach = MathUtil.map(0.008/2.0, 0, del, 0, 1.0);
|
||||
|
||||
// Interpolate to get CD
|
||||
double cd = MathUtil.map(mach, 0.2, 0.3, 1.22, 1.25);
|
||||
|
||||
// Reference area of rail button
|
||||
final double outerArea = button.getTotalHeight() * button.getOuterDiameter();
|
||||
final double notchArea = (button.getOuterDiameter() - button.getInnerDiameter()) * button.getInnerHeight();
|
||||
final double refArea = outerArea - notchArea;
|
||||
|
||||
// Get "effective" CD
|
||||
double calccd = cd * MathUtil.pow2(mach) * barrowmanObj.calculateStagnationCD(conditions.getMach()) * refArea / conditions.getRefArea() ;
|
||||
|
||||
// Now compare with value from RailButtonCalc
|
||||
WarningSet warnings = new WarningSet();
|
||||
AerodynamicForces assemblyForces = new AerodynamicForces().zero();
|
||||
AerodynamicForces componentForces = new AerodynamicForces();
|
||||
|
||||
double testcd = calcObj.calculatePressureCD(conditions, barrowmanObj.calculateStagnationCD(conditions.getMach()), 0, warnings);
|
||||
|
||||
assertEquals("Calculated rail button CD incorrect", calccd, testcd, EPSILON);
|
||||
}
|
||||
}
|
||||
@ -23,7 +23,7 @@ public class ThrustCurveMotorSetTest {
|
||||
private static final ThrustCurveMotor motor1 = new ThrustCurveMotor.Builder()
|
||||
.setManufacturer(Manufacturer.getManufacturer("A"))
|
||||
.setCommonName("F12")
|
||||
.setDesignation("F12X")
|
||||
.setDesignation("F12")
|
||||
.setDescription("Desc")
|
||||
.setMotorType(Motor.Type.UNKNOWN)
|
||||
.setStandardDelays(new double[] {})
|
||||
@ -38,7 +38,7 @@ public class ThrustCurveMotorSetTest {
|
||||
private static final ThrustCurveMotor motor2 = new ThrustCurveMotor.Builder()
|
||||
.setManufacturer(Manufacturer.getManufacturer("A"))
|
||||
.setCommonName("F12")
|
||||
.setDesignation("F12H")
|
||||
.setDesignation("F12")
|
||||
.setDescription("Desc")
|
||||
.setMotorType(Motor.Type.SINGLE)
|
||||
.setStandardDelays(new double[] { 5 })
|
||||
@ -51,20 +51,6 @@ public class ThrustCurveMotorSetTest {
|
||||
.build();
|
||||
|
||||
private static final ThrustCurveMotor motor3 = new ThrustCurveMotor.Builder()
|
||||
.setManufacturer(Manufacturer.getManufacturer("A"))
|
||||
.setCode("F12")
|
||||
.setDescription("Desc")
|
||||
.setMotorType(Motor.Type.UNKNOWN)
|
||||
.setStandardDelays(new double[] { 0, Motor.PLUGGED_DELAY })
|
||||
.setDiameter(0.024)
|
||||
.setLength(0.07)
|
||||
.setTimePoints(new double[] { 0, 1, 2 })
|
||||
.setThrustPoints(new double[] { 0, 2, 0 })
|
||||
.setCGPoints(new Coordinate[] { Coordinate.NUL, Coordinate.NUL, Coordinate.NUL })
|
||||
.setDigest("digestC")
|
||||
.build();
|
||||
|
||||
private static final ThrustCurveMotor motor4 = new ThrustCurveMotor.Builder()
|
||||
.setManufacturer(Manufacturer.getManufacturer("A"))
|
||||
.setDesignation("F12")
|
||||
.setDescription("Desc")
|
||||
@ -113,39 +99,20 @@ public class ThrustCurveMotorSetTest {
|
||||
// Add motor2
|
||||
assertTrue(set.matches(motor2));
|
||||
set.addMotor(motor2);
|
||||
assertEquals(motor1.getManufacturer(), set.getManufacturer());
|
||||
assertEquals(motor3.getCommonName(), set.getCommonName());
|
||||
assertEquals(motor2.getManufacturer(), set.getManufacturer());
|
||||
assertEquals(motor2.getCommonName(), set.getCommonName());
|
||||
assertEquals(Motor.Type.SINGLE, set.getType());
|
||||
assertEquals(motor1.getDiameter(), set.getDiameter(), 0.00001);
|
||||
assertEquals(motor1.getLength(), set.getLength(), 0.00001);
|
||||
assertEquals(motor2.getDiameter(), set.getDiameter(), 0.00001);
|
||||
assertEquals(motor2.getLength(), set.getLength(), 0.00001);
|
||||
assertEquals(2, set.getMotors().size());
|
||||
assertEquals(motor2, set.getMotors().get(0));
|
||||
assertEquals(motor1, set.getMotors().get(1));
|
||||
assertEquals(motor1, set.getMotors().get(0));
|
||||
assertEquals(motor2, set.getMotors().get(1));
|
||||
assertEquals(Arrays.asList(5.0), set.getDelays());
|
||||
|
||||
// Add motor3
|
||||
assertTrue(set.matches(motor3));
|
||||
set.addMotor(motor3);
|
||||
assertEquals(motor1.getManufacturer(), set.getManufacturer());
|
||||
assertEquals(motor3.getCommonName(), set.getCommonName());
|
||||
assertEquals(Motor.Type.SINGLE, set.getType());
|
||||
assertEquals(motor1.getDiameter(), set.getDiameter(), 0.00001);
|
||||
assertEquals(motor1.getLength(), set.getLength(), 0.00001);
|
||||
assertEquals(3, set.getMotors().size());
|
||||
System.out.println("motor set");
|
||||
System.out.println(set.getMotors());
|
||||
System.out.println(motor3);
|
||||
System.out.println(motor2);
|
||||
System.out.println(motor1);
|
||||
assertEquals(motor3, set.getMotors().get(0));
|
||||
assertEquals(motor2, set.getMotors().get(1));
|
||||
assertEquals(motor1, set.getMotors().get(2));
|
||||
assertEquals(Arrays.asList(0.0, 5.0, Motor.PLUGGED_DELAY), set.getDelays());
|
||||
|
||||
// Test that adding motor4 fails
|
||||
assertFalse(set.matches(motor4));
|
||||
// Test that adding motor3 fails
|
||||
assertFalse(set.matches(motor3));
|
||||
try {
|
||||
set.addMotor(motor4);
|
||||
set.addMotor(motor3);
|
||||
fail("Did not throw exception");
|
||||
} catch (IllegalArgumentException e) {
|
||||
}
|
||||
|
||||
@ -3,6 +3,7 @@ package net.sf.openrocket.file.iterator;
|
||||
import static org.junit.Assert.*;
|
||||
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.File;
|
||||
import java.io.InputStream;
|
||||
|
||||
import net.sf.openrocket.util.Pair;
|
||||
@ -13,14 +14,14 @@ public class TestFileIterator {
|
||||
|
||||
@Test
|
||||
public void testFileIterator() {
|
||||
final Pair<String, InputStream> one = new Pair<String, InputStream>("one", new ByteArrayInputStream(new byte[] { 1 }));
|
||||
final Pair<String, InputStream> two = new Pair<String, InputStream>("two", new ByteArrayInputStream(new byte[] { 2 }));
|
||||
final Pair<File, InputStream> one = new Pair<>(new File("one"), new ByteArrayInputStream(new byte[] { 1 }));
|
||||
final Pair<File, InputStream> two = new Pair<>(new File("two"), new ByteArrayInputStream(new byte[] { 2 }));
|
||||
|
||||
FileIterator iterator = new FileIterator() {
|
||||
private int count = 0;
|
||||
|
||||
@Override
|
||||
protected Pair<String, InputStream> findNext() {
|
||||
protected Pair<File, InputStream> findNext() {
|
||||
count++;
|
||||
switch (count) {
|
||||
case 1:
|
||||
|
||||
398
core/test/net/sf/openrocket/rocketcomponent/NoseConeTest.java
Normal file
@ -0,0 +1,398 @@
|
||||
package net.sf.openrocket.rocketcomponent;
|
||||
|
||||
import net.sf.openrocket.document.OpenRocketDocumentFactory;
|
||||
import net.sf.openrocket.util.BaseTestCase.BaseTestCase;
|
||||
import net.sf.openrocket.util.MathUtil;
|
||||
import org.junit.Test;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertFalse;
|
||||
import static org.junit.Assert.assertNull;
|
||||
import static org.junit.Assert.assertSame;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
|
||||
public class NoseConeTest extends BaseTestCase {
|
||||
private final double EPSILON = MathUtil.EPSILON * 1000;
|
||||
|
||||
@Test
|
||||
public void testNormalNoseCone() {
|
||||
NoseCone noseCone = new NoseCone();
|
||||
|
||||
// First set the parameters using the normal transition setters (i.e. using AftRadius and AftShoulder instead of Base and Shoulder)
|
||||
noseCone.setType(Transition.Shape.OGIVE);
|
||||
noseCone.setLength(0.06);
|
||||
noseCone.setAftRadius(0.1);
|
||||
noseCone.setAftShoulderLength(0.01);
|
||||
noseCone.setAftShoulderRadius(0.05);
|
||||
noseCone.setAftShoulderCapped(false);
|
||||
noseCone.setAftShoulderThickness(0.001);
|
||||
|
||||
assertEquals(Transition.Shape.OGIVE, noseCone.getType());
|
||||
assertEquals(0.06, noseCone.getLength(), EPSILON);
|
||||
assertEquals(0.1, noseCone.getAftRadius(), EPSILON);
|
||||
assertEquals(0.1, noseCone.getBaseRadius(), EPSILON);
|
||||
assertEquals(0.1, noseCone.getAftRadiusNoAutomatic(), EPSILON);
|
||||
assertEquals(0.1, noseCone.getBaseRadiusNoAutomatic(), EPSILON);
|
||||
assertEquals(0.01, noseCone.getAftShoulderLength(), EPSILON);
|
||||
assertEquals(0.01, noseCone.getShoulderLength(), EPSILON);
|
||||
assertEquals(0.05, noseCone.getAftShoulderRadius(), EPSILON);
|
||||
assertEquals(0.05, noseCone.getShoulderRadius(), EPSILON);
|
||||
assertFalse(noseCone.isAftShoulderCapped());
|
||||
assertFalse(noseCone.isShoulderCapped());
|
||||
assertEquals(0.001, noseCone.getAftShoulderThickness(), EPSILON);
|
||||
assertEquals(0.001, noseCone.getShoulderThickness(), EPSILON);
|
||||
assertFalse(noseCone.isAftRadiusAutomatic());
|
||||
|
||||
assertEquals(0, noseCone.getForeRadius(), EPSILON);
|
||||
assertEquals(0, noseCone.getForeRadiusNoAutomatic(), EPSILON);
|
||||
assertEquals(0, noseCone.getForeShoulderLength(), EPSILON);
|
||||
assertEquals(0, noseCone.getForeShoulderRadius(), EPSILON);
|
||||
assertEquals(0, noseCone.getForeShoulderThickness(), EPSILON);
|
||||
assertFalse(noseCone.isForeShoulderCapped());
|
||||
assertFalse(noseCone.isForeRadiusAutomatic());
|
||||
|
||||
// Test setting the specific nose cone setters
|
||||
noseCone.setBaseRadius(0.2);
|
||||
noseCone.setShoulderLength(0.03);
|
||||
noseCone.setShoulderRadius(0.04);
|
||||
noseCone.setShoulderCapped(true);
|
||||
noseCone.setShoulderThickness(0.005);
|
||||
|
||||
assertEquals(0.2, noseCone.getAftRadius(), EPSILON);
|
||||
assertEquals(0.2, noseCone.getBaseRadius(), EPSILON);
|
||||
assertEquals(0.2, noseCone.getAftRadiusNoAutomatic(), EPSILON);
|
||||
assertEquals(0.2, noseCone.getBaseRadiusNoAutomatic(), EPSILON);
|
||||
assertEquals(0.03, noseCone.getAftShoulderLength(), EPSILON);
|
||||
assertEquals(0.03, noseCone.getShoulderLength(), EPSILON);
|
||||
assertEquals(0.04, noseCone.getAftShoulderRadius(), EPSILON);
|
||||
assertEquals(0.04, noseCone.getShoulderRadius(), EPSILON);
|
||||
assertTrue(noseCone.isAftShoulderCapped());
|
||||
assertTrue(noseCone.isShoulderCapped());
|
||||
assertEquals(0.005, noseCone.getAftShoulderThickness(), EPSILON);
|
||||
assertEquals(0.005, noseCone.getShoulderThickness(), EPSILON);
|
||||
assertFalse(noseCone.isAftRadiusAutomatic());
|
||||
|
||||
assertEquals(0, noseCone.getForeRadius(), EPSILON);
|
||||
assertEquals(0, noseCone.getForeRadiusNoAutomatic(), EPSILON);
|
||||
assertEquals(0, noseCone.getForeShoulderLength(), EPSILON);
|
||||
assertEquals(0, noseCone.getForeShoulderRadius(), EPSILON);
|
||||
assertEquals(0, noseCone.getForeShoulderThickness(), EPSILON);
|
||||
assertFalse(noseCone.isForeShoulderCapped());
|
||||
assertFalse(noseCone.isForeRadiusAutomatic());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testFlippedNoseCone() {
|
||||
NoseCone noseCone = new NoseCone();
|
||||
|
||||
// First set the parameters using the normal transition setters (i.e. using AftRadius and AftShoulder instead of Base and Shoulder)
|
||||
noseCone.setType(Transition.Shape.OGIVE);
|
||||
noseCone.setLength(0.06);
|
||||
noseCone.setAftRadius(0.1);
|
||||
noseCone.setAftShoulderLength(0.01);
|
||||
noseCone.setAftShoulderRadius(0.05);
|
||||
noseCone.setAftShoulderCapped(false);
|
||||
noseCone.setAftShoulderThickness(0.001);
|
||||
noseCone.setFlipped(true);
|
||||
|
||||
assertEquals(Transition.Shape.OGIVE, noseCone.getType());
|
||||
assertEquals(0.06, noseCone.getLength(), EPSILON);
|
||||
assertEquals(0.1, noseCone.getForeRadius(), EPSILON);
|
||||
assertEquals(0.1, noseCone.getBaseRadius(), EPSILON);
|
||||
assertEquals(0.1, noseCone.getForeRadiusNoAutomatic(), EPSILON);
|
||||
assertEquals(0.1, noseCone.getBaseRadiusNoAutomatic(), EPSILON);
|
||||
assertEquals(0.01, noseCone.getForeShoulderLength(), EPSILON);
|
||||
assertEquals(0.01, noseCone.getShoulderLength(), EPSILON);
|
||||
assertEquals(0.05, noseCone.getForeShoulderRadius(), EPSILON);
|
||||
assertEquals(0.05, noseCone.getShoulderRadius(), EPSILON);
|
||||
assertFalse(noseCone.isForeShoulderCapped());
|
||||
assertFalse(noseCone.isShoulderCapped());
|
||||
assertEquals(0.001, noseCone.getForeShoulderThickness(), EPSILON);
|
||||
assertEquals(0.001, noseCone.getShoulderThickness(), EPSILON);
|
||||
assertFalse(noseCone.isForeRadiusAutomatic());
|
||||
|
||||
assertEquals(0, noseCone.getAftRadius(), EPSILON);
|
||||
assertEquals(0, noseCone.getAftRadiusNoAutomatic(), EPSILON);
|
||||
assertEquals(0, noseCone.getAftShoulderLength(), EPSILON);
|
||||
assertEquals(0, noseCone.getAftShoulderRadius(), EPSILON);
|
||||
assertEquals(0, noseCone.getAftShoulderThickness(), EPSILON);
|
||||
assertFalse(noseCone.isAftShoulderCapped());
|
||||
assertFalse(noseCone.isAftRadiusAutomatic());
|
||||
|
||||
// Test setting the specific nose cone setters
|
||||
noseCone.setBaseRadius(0.2);
|
||||
noseCone.setShoulderLength(0.03);
|
||||
noseCone.setShoulderRadius(0.04);
|
||||
noseCone.setShoulderCapped(true);
|
||||
noseCone.setShoulderThickness(0.005);
|
||||
|
||||
assertEquals(0.2, noseCone.getForeRadius(), EPSILON);
|
||||
assertEquals(0.2, noseCone.getBaseRadius(), EPSILON);
|
||||
assertEquals(0.2, noseCone.getForeRadiusNoAutomatic(), EPSILON);
|
||||
assertEquals(0.2, noseCone.getBaseRadiusNoAutomatic(), EPSILON);
|
||||
assertEquals(0.03, noseCone.getForeShoulderLength(), EPSILON);
|
||||
assertEquals(0.03, noseCone.getShoulderLength(), EPSILON);
|
||||
assertEquals(0.04, noseCone.getForeShoulderRadius(), EPSILON);
|
||||
assertEquals(0.04, noseCone.getShoulderRadius(), EPSILON);
|
||||
assertTrue(noseCone.isForeShoulderCapped());
|
||||
assertTrue(noseCone.isShoulderCapped());
|
||||
assertEquals(0.005, noseCone.getForeShoulderThickness(), EPSILON);
|
||||
assertEquals(0.005, noseCone.getShoulderThickness(), EPSILON);
|
||||
assertFalse(noseCone.isForeRadiusAutomatic());
|
||||
|
||||
assertEquals(0, noseCone.getAftRadius(), EPSILON);
|
||||
assertEquals(0, noseCone.getAftRadiusNoAutomatic(), EPSILON);
|
||||
assertEquals(0, noseCone.getAftShoulderLength(), EPSILON);
|
||||
assertEquals(0, noseCone.getAftShoulderRadius(), EPSILON);
|
||||
assertEquals(0, noseCone.getAftShoulderThickness(), EPSILON);
|
||||
assertFalse(noseCone.isAftShoulderCapped());
|
||||
assertFalse(noseCone.isAftRadiusAutomatic());
|
||||
|
||||
// Flip back to normal
|
||||
noseCone.setFlipped(false);
|
||||
|
||||
assertEquals(0.2, noseCone.getAftRadius(), EPSILON);
|
||||
assertEquals(0.2, noseCone.getBaseRadius(), EPSILON);
|
||||
assertEquals(0.2, noseCone.getAftRadiusNoAutomatic(), EPSILON);
|
||||
assertEquals(0.2, noseCone.getBaseRadiusNoAutomatic(), EPSILON);
|
||||
assertEquals(0.03, noseCone.getAftShoulderLength(), EPSILON);
|
||||
assertEquals(0.03, noseCone.getShoulderLength(), EPSILON);
|
||||
assertEquals(0.04, noseCone.getAftShoulderRadius(), EPSILON);
|
||||
assertEquals(0.04, noseCone.getShoulderRadius(), EPSILON);
|
||||
assertTrue(noseCone.isAftShoulderCapped());
|
||||
assertTrue(noseCone.isShoulderCapped());
|
||||
assertEquals(0.005, noseCone.getAftShoulderThickness(), EPSILON);
|
||||
assertEquals(0.005, noseCone.getShoulderThickness(), EPSILON);
|
||||
assertFalse(noseCone.isAftRadiusAutomatic());
|
||||
|
||||
assertEquals(0, noseCone.getForeRadius(), EPSILON);
|
||||
assertEquals(0, noseCone.getForeRadiusNoAutomatic(), EPSILON);
|
||||
assertEquals(0, noseCone.getForeShoulderLength(), EPSILON);
|
||||
assertEquals(0, noseCone.getForeShoulderRadius(), EPSILON);
|
||||
assertEquals(0, noseCone.getForeShoulderThickness(), EPSILON);
|
||||
assertFalse(noseCone.isForeShoulderCapped());
|
||||
assertFalse(noseCone.isForeRadiusAutomatic());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testNormalNoseConeRadiusAutomatic() {
|
||||
Rocket rocket = OpenRocketDocumentFactory.createNewRocket().getRocket();
|
||||
AxialStage stage = rocket.getStage(0);
|
||||
|
||||
NoseCone noseCone = new NoseCone(Transition.Shape.CONICAL, 0.06, 0.01);
|
||||
BodyTube tube1 = new BodyTube(0.06, 0.02);
|
||||
tube1.setOuterRadiusAutomatic(false);
|
||||
BodyTube tube2 = new BodyTube(0.06, 0.03);
|
||||
tube2.setOuterRadiusAutomatic(false);
|
||||
|
||||
// Test no previous or next component
|
||||
stage.addChild(noseCone);
|
||||
|
||||
assertFalse(noseCone.usesPreviousCompAutomatic());
|
||||
assertFalse(noseCone.usesNextCompAutomatic());
|
||||
assertSame(stage, noseCone.getPreviousComponent());
|
||||
assertNull(noseCone.getPreviousSymmetricComponent());
|
||||
assertNull(noseCone.getNextComponent());
|
||||
assertNull(noseCone.getNextSymmetricComponent());
|
||||
assertFalse(noseCone.isAftRadiusAutomatic());
|
||||
assertFalse(noseCone.isBaseRadiusAutomatic());
|
||||
assertFalse(noseCone.isForeRadiusAutomatic());
|
||||
assertEquals(noseCone.getAftRadius(), noseCone.getAftRadiusNoAutomatic(), EPSILON);
|
||||
assertEquals(noseCone.getBaseRadius(), noseCone.getBaseRadiusNoAutomatic(), EPSILON);
|
||||
assertEquals(noseCone.getForeRadius(), noseCone.getForeRadiusNoAutomatic(), EPSILON);
|
||||
assertEquals(0.01, noseCone.getAftRadiusNoAutomatic(), EPSILON);
|
||||
assertEquals(0, noseCone.getForeRadiusNoAutomatic(), EPSILON);
|
||||
|
||||
noseCone.setAftRadiusAutomatic(true, true);
|
||||
assertFalse(noseCone.isAftRadiusAutomatic());
|
||||
assertFalse(noseCone.isBaseRadiusAutomatic());
|
||||
noseCone.setForeRadiusAutomatic(true, true);
|
||||
assertFalse(noseCone.isForeRadiusAutomatic());
|
||||
assertFalse(noseCone.isBaseRadiusAutomatic());
|
||||
|
||||
// Test with next component
|
||||
stage.addChild(tube1);
|
||||
|
||||
assertFalse(noseCone.usesPreviousCompAutomatic());
|
||||
assertFalse(noseCone.usesNextCompAutomatic());
|
||||
assertSame(stage, noseCone.getPreviousComponent());
|
||||
assertNull(noseCone.getPreviousSymmetricComponent());
|
||||
assertSame(tube1, noseCone.getNextComponent());
|
||||
assertSame(tube1, noseCone.getNextSymmetricComponent());
|
||||
assertFalse(noseCone.isAftRadiusAutomatic());
|
||||
assertFalse(noseCone.isBaseRadiusAutomatic());
|
||||
assertFalse(noseCone.isForeRadiusAutomatic());
|
||||
assertEquals(noseCone.getAftRadius(), noseCone.getAftRadiusNoAutomatic(), EPSILON);
|
||||
assertEquals(noseCone.getBaseRadius(), noseCone.getBaseRadiusNoAutomatic(), EPSILON);
|
||||
assertEquals(noseCone.getForeRadius(), noseCone.getForeRadiusNoAutomatic(), EPSILON);
|
||||
assertEquals(0, noseCone.getForeRadiusNoAutomatic(), EPSILON);
|
||||
|
||||
noseCone.setAftRadiusAutomatic(true, true);
|
||||
assertFalse(noseCone.usesPreviousCompAutomatic());
|
||||
assertTrue(noseCone.usesNextCompAutomatic());
|
||||
assertSame(stage, noseCone.getPreviousComponent());
|
||||
assertNull(noseCone.getPreviousSymmetricComponent());
|
||||
assertSame(tube1, noseCone.getNextComponent());
|
||||
assertSame(tube1, noseCone.getNextSymmetricComponent());
|
||||
assertTrue(noseCone.isAftRadiusAutomatic());
|
||||
assertTrue(noseCone.isBaseRadiusAutomatic());
|
||||
assertFalse(noseCone.isForeRadiusAutomatic());
|
||||
assertEquals(tube1.getForeRadius(), noseCone.getAftRadius(), EPSILON);
|
||||
assertEquals(0.01, noseCone.getAftRadiusNoAutomatic(), EPSILON);
|
||||
assertEquals(tube1.getForeRadius(), noseCone.getBaseRadius(), EPSILON);
|
||||
assertEquals(0.01, noseCone.getBaseRadiusNoAutomatic(), EPSILON);
|
||||
assertEquals(noseCone.getForeRadius(), noseCone.getForeRadiusNoAutomatic(), EPSILON);
|
||||
assertEquals(0, noseCone.getForeRadiusNoAutomatic(), EPSILON);
|
||||
|
||||
noseCone.setAftRadiusAutomatic(false, true);
|
||||
assertEquals(noseCone.getAftRadius(), noseCone.getAftRadiusNoAutomatic(), EPSILON);
|
||||
assertEquals(noseCone.getBaseRadius(), noseCone.getBaseRadiusNoAutomatic(), EPSILON);
|
||||
assertEquals(noseCone.getForeRadius(), noseCone.getForeRadiusNoAutomatic(), EPSILON);
|
||||
assertEquals(0, noseCone.getForeRadiusNoAutomatic(), EPSILON);
|
||||
|
||||
noseCone.setBaseRadiusAutomatic(true);
|
||||
assertEquals(0.01, noseCone.getAftRadiusNoAutomatic(), EPSILON);
|
||||
assertEquals(tube1.getForeRadius(), noseCone.getBaseRadius(), EPSILON);
|
||||
assertEquals(0.01, noseCone.getBaseRadiusNoAutomatic(), EPSILON);
|
||||
assertEquals(noseCone.getForeRadius(), noseCone.getForeRadiusNoAutomatic(), EPSILON);
|
||||
assertEquals(0, noseCone.getForeRadiusNoAutomatic(), EPSILON);
|
||||
|
||||
noseCone.setForeRadiusAutomatic(true, true);
|
||||
assertFalse(noseCone.isForeRadiusAutomatic());
|
||||
assertTrue(noseCone.isBaseRadiusAutomatic());
|
||||
|
||||
// Test with previous component
|
||||
stage.addChild(tube2, 0);
|
||||
|
||||
assertFalse(noseCone.usesPreviousCompAutomatic());
|
||||
assertTrue(noseCone.usesNextCompAutomatic());
|
||||
assertSame(tube2, noseCone.getPreviousComponent());
|
||||
assertSame(tube2, noseCone.getPreviousSymmetricComponent());
|
||||
assertSame(tube1, noseCone.getNextComponent());
|
||||
assertSame(tube1, noseCone.getNextSymmetricComponent());
|
||||
assertTrue(noseCone.isAftRadiusAutomatic());
|
||||
assertTrue(noseCone.isBaseRadiusAutomatic());
|
||||
assertFalse(noseCone.isForeRadiusAutomatic());
|
||||
assertEquals(tube1.getForeRadius(), noseCone.getAftRadius(), EPSILON);
|
||||
assertEquals(0.01, noseCone.getAftRadiusNoAutomatic(), EPSILON);
|
||||
assertEquals(tube1.getForeRadius(), noseCone.getBaseRadius(), EPSILON);
|
||||
assertEquals(0.01, noseCone.getBaseRadiusNoAutomatic(), EPSILON);
|
||||
assertEquals(noseCone.getForeRadius(), noseCone.getForeRadiusNoAutomatic(), EPSILON);
|
||||
assertEquals(0, noseCone.getForeRadiusNoAutomatic(), EPSILON);
|
||||
|
||||
// Do a flip
|
||||
noseCone.setFlipped(true);
|
||||
assertTrue(noseCone.isForeRadiusAutomatic());
|
||||
assertTrue(noseCone.isBaseRadiusAutomatic());
|
||||
assertFalse(noseCone.isAftRadiusAutomatic());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testFlippedNoseConeRadiusAutomatic() {
|
||||
Rocket rocket = OpenRocketDocumentFactory.createNewRocket().getRocket();
|
||||
AxialStage stage = rocket.getStage(0);
|
||||
|
||||
NoseCone noseCone = new NoseCone(Transition.Shape.CONICAL, 0.06, 0.01);
|
||||
noseCone.setFlipped(true);
|
||||
BodyTube tube1 = new BodyTube(0.06, 0.02);
|
||||
tube1.setOuterRadiusAutomatic(false);
|
||||
BodyTube tube2 = new BodyTube(0.06, 0.03);
|
||||
tube2.setOuterRadiusAutomatic(false);
|
||||
|
||||
// Test no previous or next component
|
||||
stage.addChild(noseCone);
|
||||
|
||||
assertFalse(noseCone.usesPreviousCompAutomatic());
|
||||
assertFalse(noseCone.usesNextCompAutomatic());
|
||||
assertSame(stage, noseCone.getPreviousComponent());
|
||||
assertNull(noseCone.getPreviousSymmetricComponent());
|
||||
assertNull(noseCone.getNextComponent());
|
||||
assertNull(noseCone.getNextSymmetricComponent());
|
||||
assertFalse(noseCone.isAftRadiusAutomatic());
|
||||
assertFalse(noseCone.isBaseRadiusAutomatic());
|
||||
assertFalse(noseCone.isForeRadiusAutomatic());
|
||||
assertEquals(noseCone.getAftRadius(), noseCone.getAftRadiusNoAutomatic(), EPSILON);
|
||||
assertEquals(noseCone.getBaseRadius(), noseCone.getBaseRadiusNoAutomatic(), EPSILON);
|
||||
assertEquals(noseCone.getForeRadius(), noseCone.getForeRadiusNoAutomatic(), EPSILON);
|
||||
assertEquals(0, noseCone.getAftRadiusNoAutomatic(), EPSILON);
|
||||
assertEquals(0.01, noseCone.getForeRadiusNoAutomatic(), EPSILON);
|
||||
|
||||
noseCone.setAftRadiusAutomatic(true, true);
|
||||
assertFalse(noseCone.isAftRadiusAutomatic());
|
||||
assertFalse(noseCone.isBaseRadiusAutomatic());
|
||||
noseCone.setForeRadiusAutomatic(true, true);
|
||||
assertFalse(noseCone.isForeRadiusAutomatic());
|
||||
assertFalse(noseCone.isBaseRadiusAutomatic());
|
||||
|
||||
// Test with previous component
|
||||
stage.addChild(tube1, 0);
|
||||
|
||||
assertFalse(noseCone.usesPreviousCompAutomatic());
|
||||
assertFalse(noseCone.usesNextCompAutomatic());
|
||||
assertSame(tube1, noseCone.getPreviousComponent());
|
||||
assertSame(tube1, noseCone.getPreviousSymmetricComponent());
|
||||
assertNull(noseCone.getNextComponent());
|
||||
assertNull(noseCone.getNextSymmetricComponent());
|
||||
assertFalse(noseCone.isAftRadiusAutomatic());
|
||||
assertFalse(noseCone.isBaseRadiusAutomatic());
|
||||
assertFalse(noseCone.isForeRadiusAutomatic());
|
||||
assertEquals(noseCone.getAftRadius(), noseCone.getAftRadiusNoAutomatic(), EPSILON);
|
||||
assertEquals(noseCone.getBaseRadius(), noseCone.getBaseRadiusNoAutomatic(), EPSILON);
|
||||
assertEquals(noseCone.getForeRadius(), noseCone.getForeRadiusNoAutomatic(), EPSILON);
|
||||
assertEquals(0, noseCone.getAftRadiusNoAutomatic(), EPSILON);
|
||||
|
||||
noseCone.setBaseRadiusAutomatic(true);
|
||||
assertTrue(noseCone.usesPreviousCompAutomatic());
|
||||
assertFalse(noseCone.usesNextCompAutomatic());
|
||||
assertSame(tube1, noseCone.getPreviousComponent());
|
||||
assertSame(tube1, noseCone.getPreviousSymmetricComponent());
|
||||
assertNull(noseCone.getNextComponent());
|
||||
assertNull(noseCone.getNextSymmetricComponent());
|
||||
assertFalse(noseCone.isAftRadiusAutomatic());
|
||||
assertTrue(noseCone.isBaseRadiusAutomatic());
|
||||
assertTrue(noseCone.isForeRadiusAutomatic());
|
||||
assertEquals(tube1.getAftRadius(), noseCone.getForeRadius(), EPSILON);
|
||||
assertEquals(0.01, noseCone.getForeRadiusNoAutomatic(), EPSILON);
|
||||
assertEquals(tube1.getAftRadius(), noseCone.getBaseRadius(), EPSILON);
|
||||
assertEquals(0.01, noseCone.getBaseRadiusNoAutomatic(), EPSILON);
|
||||
assertEquals(noseCone.getAftRadius(), noseCone.getAftRadiusNoAutomatic(), EPSILON);
|
||||
assertEquals(0, noseCone.getAftRadiusNoAutomatic(), EPSILON);
|
||||
|
||||
noseCone.setForeRadiusAutomatic(false, true);
|
||||
assertEquals(noseCone.getAftRadius(), noseCone.getAftRadiusNoAutomatic(), EPSILON);
|
||||
assertEquals(noseCone.getBaseRadius(), noseCone.getBaseRadiusNoAutomatic(), EPSILON);
|
||||
assertEquals(noseCone.getForeRadius(), noseCone.getForeRadiusNoAutomatic(), EPSILON);
|
||||
assertEquals(0.01, noseCone.getForeRadiusNoAutomatic(), EPSILON);
|
||||
|
||||
noseCone.setBaseRadiusAutomatic(true);
|
||||
assertEquals(tube1.getAftRadius(), noseCone.getForeRadius(), EPSILON);
|
||||
assertEquals(0.01, noseCone.getForeRadiusNoAutomatic(), EPSILON);
|
||||
assertEquals(tube1.getAftRadius(), noseCone.getBaseRadius(), EPSILON);
|
||||
assertEquals(0.01, noseCone.getBaseRadiusNoAutomatic(), EPSILON);
|
||||
assertEquals(noseCone.getAftRadius(), noseCone.getAftRadiusNoAutomatic(), EPSILON);
|
||||
assertEquals(0, noseCone.getAftRadiusNoAutomatic(), EPSILON);
|
||||
|
||||
assertTrue(noseCone.isForeRadiusAutomatic());
|
||||
assertTrue(noseCone.isBaseRadiusAutomatic());
|
||||
assertFalse(noseCone.isAftRadiusAutomatic());
|
||||
|
||||
// Test with next component
|
||||
stage.addChild(tube2);
|
||||
|
||||
assertTrue(noseCone.usesPreviousCompAutomatic());
|
||||
assertFalse(noseCone.usesNextCompAutomatic());
|
||||
assertSame(tube1, noseCone.getPreviousComponent());
|
||||
assertSame(tube1, noseCone.getPreviousSymmetricComponent());
|
||||
assertSame(tube2, noseCone.getNextComponent());
|
||||
assertSame(tube2, noseCone.getNextSymmetricComponent());
|
||||
assertFalse(noseCone.isAftRadiusAutomatic());
|
||||
assertTrue(noseCone.isBaseRadiusAutomatic());
|
||||
assertTrue(noseCone.isForeRadiusAutomatic());
|
||||
assertEquals(tube1.getAftRadius(), noseCone.getForeRadius(), EPSILON);
|
||||
assertEquals(0.01, noseCone.getForeRadiusNoAutomatic(), EPSILON);
|
||||
assertEquals(tube1.getForeRadius(), noseCone.getBaseRadius(), EPSILON);
|
||||
assertEquals(0.01, noseCone.getBaseRadiusNoAutomatic(), EPSILON);
|
||||
assertEquals(noseCone.getAftRadius(), noseCone.getAftRadiusNoAutomatic(), EPSILON);
|
||||
assertEquals(0, noseCone.getAftRadius(), EPSILON);
|
||||
}
|
||||
}
|
||||
@ -24,6 +24,8 @@ import static org.junit.Assert.assertSame;
|
||||
* Tests to verify that simulations contain all the expected flight events.
|
||||
*/
|
||||
public class FlightEventsTest extends BaseTestCase {
|
||||
private static final double EPSILON = 0.005;
|
||||
|
||||
/**
|
||||
* Tests for a single stage design.
|
||||
*/
|
||||
@ -66,7 +68,7 @@ public class FlightEventsTest extends BaseTestCase {
|
||||
// Test that the event times are correct
|
||||
for (int i = 0; i < expectedEventTimes.length; i++) {
|
||||
assertEquals(" Flight type " + expectedEventTypes[i] + " has wrong time",
|
||||
expectedEventTimes[i], eventList.get(i).getTime(), 0.001);
|
||||
expectedEventTimes[i], eventList.get(i).getTime(), EPSILON);
|
||||
|
||||
}
|
||||
|
||||
@ -142,7 +144,7 @@ public class FlightEventsTest extends BaseTestCase {
|
||||
// Test that the event times are correct
|
||||
for (int i = 0; i < expectedEventTimes.length; i++) {
|
||||
assertEquals(" Flight type " + expectedEventTypes[i] + " has wrong time",
|
||||
expectedEventTimes[i], eventList.get(i).getTime(), 0.001);
|
||||
expectedEventTimes[i], eventList.get(i).getTime(), EPSILON);
|
||||
}
|
||||
|
||||
// Test that the event sources are correct
|
||||
|
||||
@ -58,6 +58,7 @@ The following file format versions exist:
|
||||
Added PhotoStudio settings saving (<photostudio>)
|
||||
Added override CD parameter (<overridecd>)
|
||||
Added stage activeness remembrance (<stage> under <motorconfiguration>)
|
||||
Added <isflipped> parameter for Nose Cones
|
||||
Separated <overridesubcomponents> into individual parameters for mass, CG, and CD.
|
||||
Rename <fincount> to <instancecount> (<fincount> remains for backward compatibility)
|
||||
Rename <position> to <axialoffset> (<position> remains for backward compatibility)
|
||||
|
||||
@ -19,7 +19,7 @@
|
||||
<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/lib/javax.activation-api.2.3.1.jar"/>
|
||||
<classpathentry kind="lib" path="/OpenRocket Core/lib/javax.activation-api-2.3.1.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"/>
|
||||
|
||||