Merge pull request #2416 from SiboVG/issue-2178

[#2178] Add South/West unit for latitude/longitude
This commit is contained in:
Sibo Van Gool 2023-12-09 02:03:15 +01:00 committed by GitHub
commit c136436284
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 221 additions and 174 deletions

View File

@ -374,6 +374,8 @@ pref.dlg.lbl.SecondaryStability.ttip = Select the stability unit that will be di
pref.dlg.checkbox.DisplaySecondaryStability = Display secondary stability unit pref.dlg.checkbox.DisplaySecondaryStability = Display secondary stability unit
pref.dlg.checkbox.DisplaySecondaryStability.ttip = If checked, a secondary stability unit will be displayed in the rocket design view. pref.dlg.checkbox.DisplaySecondaryStability.ttip = If checked, a secondary stability unit will be displayed in the rocket design view.
pref.dlg.lbl.FlightTime = Flight time: pref.dlg.lbl.FlightTime = Flight time:
pref.dlg.lbl.Latitude = Latitude:
pref.dlg.lbl.Longitude = Longitude:
pref.dlg.lbl.effect1 = The effects will take place the next time you open a window. pref.dlg.lbl.effect1 = The effects will take place the next time you open a window.
pref.dlg.lbl.Checkingupdates = Checking for updates\u2026 pref.dlg.lbl.Checkingupdates = Checking for updates\u2026
pref.dlg.PrefChoiseSelector1 = Always ask pref.dlg.PrefChoiseSelector1 = Always ask

View File

@ -79,10 +79,10 @@ public class FlightDataType implements Comparable<FlightDataType> {
public static final FlightDataType TYPE_ACCELERATION_XY = newType(trans.get("FlightDataType.TYPE_ACCELERATION_XY"), "Al", UnitGroup.UNITS_ACCELERATION, public static final FlightDataType TYPE_ACCELERATION_XY = newType(trans.get("FlightDataType.TYPE_ACCELERATION_XY"), "Al", UnitGroup.UNITS_ACCELERATION,
FlightDataTypeGroup.POSITION_AND_MOTION, 5); FlightDataTypeGroup.POSITION_AND_MOTION, 5);
//// Latitude //// Latitude
public static final FlightDataType TYPE_LATITUDE = newType(trans.get("FlightDataType.TYPE_LATITUDE"), "\u03c6", UnitGroup.UNITS_ANGLE, public static final FlightDataType TYPE_LATITUDE = newType(trans.get("FlightDataType.TYPE_LATITUDE"), "\u03c6", UnitGroup.UNITS_LATITUDE,
FlightDataTypeGroup.POSITION_AND_MOTION, 6); FlightDataTypeGroup.POSITION_AND_MOTION, 6);
//// Longitude //// Longitude
public static final FlightDataType TYPE_LONGITUDE = newType(trans.get("FlightDataType.TYPE_LONGITUDE"), "\u03bb", UnitGroup.UNITS_ANGLE, public static final FlightDataType TYPE_LONGITUDE = newType(trans.get("FlightDataType.TYPE_LONGITUDE"), "\u03bb", UnitGroup.UNITS_LONGITUDE,
FlightDataTypeGroup.POSITION_AND_MOTION, 7); FlightDataTypeGroup.POSITION_AND_MOTION, 7);

View File

@ -70,6 +70,10 @@ public abstract class Unit {
return true; return true;
} }
public double getMultiplier() {
return multiplier;
}
@Override @Override
public String toString() { public String toString() {
return unit; return unit;

View File

@ -16,8 +16,11 @@ import java.util.Map;
import java.util.regex.Matcher; import java.util.regex.Matcher;
import java.util.regex.Pattern; import java.util.regex.Pattern;
import net.sf.openrocket.l10n.Translator;
import net.sf.openrocket.rocketcomponent.FlightConfiguration; import net.sf.openrocket.rocketcomponent.FlightConfiguration;
import net.sf.openrocket.rocketcomponent.Rocket; import net.sf.openrocket.rocketcomponent.Rocket;
import net.sf.openrocket.startup.Application;
import net.sf.openrocket.util.Chars;
import net.sf.openrocket.util.StringUtils; import net.sf.openrocket.util.StringUtils;
@ -49,6 +52,8 @@ public class UnitGroup {
public static final UnitGroup UNITS_STABILITY_CALIBERS; public static final UnitGroup UNITS_STABILITY_CALIBERS;
public static final UnitGroup UNITS_VELOCITY; public static final UnitGroup UNITS_VELOCITY;
public static final UnitGroup UNITS_WINDSPEED; public static final UnitGroup UNITS_WINDSPEED;
public static final UnitGroup UNITS_LATITUDE;
public static final UnitGroup UNITS_LONGITUDE;
public static final UnitGroup UNITS_ACCELERATION; public static final UnitGroup UNITS_ACCELERATION;
public static final UnitGroup UNITS_MASS; public static final UnitGroup UNITS_MASS;
public static final UnitGroup UNITS_INERTIA; public static final UnitGroup UNITS_INERTIA;
@ -88,6 +93,8 @@ public class UnitGroup {
public static final Map<String, UnitGroup> UNITS; // keys such as "LENGTH", "VELOCITY" public static final Map<String, UnitGroup> UNITS; // keys such as "LENGTH", "VELOCITY"
public static final Map<String, UnitGroup> SIUNITS; // keys such a "m", "m/s" public static final Map<String, UnitGroup> SIUNITS; // keys such a "m", "m/s"
private static final Translator trans = Application.getTranslator();
/* /*
* Note: Units may not use HTML tags. * Note: Units may not use HTML tags.
@ -192,6 +199,14 @@ public class UnitGroup {
UNITS_WINDSPEED.addUnit(new GeneralUnit(0.44704, "mph")); UNITS_WINDSPEED.addUnit(new GeneralUnit(0.44704, "mph"));
UNITS_WINDSPEED.addUnit(new GeneralUnit(0.51444445, "kt")); UNITS_WINDSPEED.addUnit(new GeneralUnit(0.51444445, "kt"));
UNITS_LATITUDE = new UnitGroup();
UNITS_LATITUDE.addUnit(new GeneralUnit(1, DEGREE + " " + trans.get("CompassRose.lbl.north")));
UNITS_LATITUDE.addUnit(new GeneralUnit(-1, DEGREE + " " + trans.get("CompassRose.lbl.south")));
UNITS_LONGITUDE = new UnitGroup();
UNITS_LONGITUDE.addUnit(new GeneralUnit(1, DEGREE + " " + trans.get("CompassRose.lbl.east")));
UNITS_LONGITUDE.addUnit(new GeneralUnit(-1, DEGREE + " " + trans.get("CompassRose.lbl.west")));
UNITS_ACCELERATION = new UnitGroup(); UNITS_ACCELERATION = new UnitGroup();
UNITS_ACCELERATION.addUnit(new GeneralUnit(1, "m/s" + SQUARED)); UNITS_ACCELERATION.addUnit(new GeneralUnit(1, "m/s" + SQUARED));
UNITS_ACCELERATION.addUnit(new GeneralUnit(0.3048, "ft/s" + SQUARED)); UNITS_ACCELERATION.addUnit(new GeneralUnit(0.3048, "ft/s" + SQUARED));
@ -346,6 +361,8 @@ public class UnitGroup {
map.put("MOMENTUM", UNITS_MOMENTUM); map.put("MOMENTUM", UNITS_MOMENTUM);
map.put("FREQUENCY", UNITS_FREQUENCY); map.put("FREQUENCY", UNITS_FREQUENCY);
map.put("WINDSPEED", UNITS_WINDSPEED); map.put("WINDSPEED", UNITS_WINDSPEED);
map.put("LATITUDE", UNITS_LATITUDE);
map.put("LONGITUDE", UNITS_LONGITUDE);
UNITS = Collections.unmodifiableMap(map); UNITS = Collections.unmodifiableMap(map);
@ -394,6 +411,8 @@ public class UnitGroup {
UNITS_ROLL.setDefaultUnit("r/s"); UNITS_ROLL.setDefaultUnit("r/s");
UNITS_TEMPERATURE.setDefaultUnit(DEGREE + "C"); UNITS_TEMPERATURE.setDefaultUnit(DEGREE + "C");
UNITS_WINDSPEED.setDefaultUnit("m/s"); UNITS_WINDSPEED.setDefaultUnit("m/s");
UNITS_LATITUDE.setDefaultUnit(DEGREE + " " + trans.get("CompassRose.lbl.north"));
UNITS_LONGITUDE.setDefaultUnit(DEGREE + " " + trans.get("CompassRose.lbl.east"));
UNITS_PRESSURE.setDefaultUnit("mbar"); UNITS_PRESSURE.setDefaultUnit("mbar");
UNITS_RELATIVE.setDefaultUnit("%"); UNITS_RELATIVE.setDefaultUnit("%");
UNITS_ROUGHNESS.setDefaultUnit(MICRO + "m"); UNITS_ROUGHNESS.setDefaultUnit(MICRO + "m");
@ -421,6 +440,8 @@ public class UnitGroup {
UNITS_ROLL.setDefaultUnit("r/s"); UNITS_ROLL.setDefaultUnit("r/s");
UNITS_TEMPERATURE.setDefaultUnit(DEGREE + "F"); UNITS_TEMPERATURE.setDefaultUnit(DEGREE + "F");
UNITS_WINDSPEED.setDefaultUnit("mph"); UNITS_WINDSPEED.setDefaultUnit("mph");
UNITS_LATITUDE.setDefaultUnit(DEGREE + " " + trans.get("CompassRose.lbl.north"));
UNITS_LONGITUDE.setDefaultUnit(DEGREE + " " + trans.get("CompassRose.lbl.east"));
UNITS_PRESSURE.setDefaultUnit("mbar"); UNITS_PRESSURE.setDefaultUnit("mbar");
UNITS_RELATIVE.setDefaultUnit("%"); UNITS_RELATIVE.setDefaultUnit("%");
UNITS_ROUGHNESS.setDefaultUnit("mil"); UNITS_ROUGHNESS.setDefaultUnit("mil");
@ -443,6 +464,8 @@ public class UnitGroup {
UNITS_STABILITY_CALIBERS.setDefaultUnit(0); UNITS_STABILITY_CALIBERS.setDefaultUnit(0);
UNITS_VELOCITY.setDefaultUnit(0); UNITS_VELOCITY.setDefaultUnit(0);
UNITS_WINDSPEED.setDefaultUnit(0); UNITS_WINDSPEED.setDefaultUnit(0);
UNITS_LATITUDE.setDefaultUnit(0);
UNITS_LONGITUDE.setDefaultUnit(0);
UNITS_ACCELERATION.setDefaultUnit(0); UNITS_ACCELERATION.setDefaultUnit(0);
UNITS_MASS.setDefaultUnit(0); UNITS_MASS.setDefaultUnit(0);
UNITS_INERTIA.setDefaultUnit(1); UNITS_INERTIA.setDefaultUnit(1);
@ -478,8 +501,8 @@ public class UnitGroup {
/** /**
* Return a UnitGroup for stability units based on the rocket. * Return a UnitGroup for stability units based on the rocket.
* *
* @param rocket the rocket from which to calculate the caliber * @param rocket the rocket from which to calculate the caliber
* @return the unit group * @return the unit group
*/ */
public static StabilityUnitGroup stabilityUnits(Rocket rocket) { public static StabilityUnitGroup stabilityUnits(Rocket rocket) {
return new StabilityUnitGroup(UnitGroup.UNITS_STABILITY, rocket); return new StabilityUnitGroup(UnitGroup.UNITS_STABILITY, rocket);
@ -499,8 +522,8 @@ public class UnitGroup {
/** /**
* Return a UnitGroup for stability units based on the rocket configuration. * Return a UnitGroup for stability units based on the rocket configuration.
* *
* @param config the rocket configuration from which to calculate the caliber * @param config the rocket configuration from which to calculate the caliber
* @return the unit group * @return the unit group
*/ */
public static StabilityUnitGroup stabilityUnits(FlightConfiguration config) { public static StabilityUnitGroup stabilityUnits(FlightConfiguration config) {
return new StabilityUnitGroup(UnitGroup.UNITS_STABILITY, config); return new StabilityUnitGroup(UnitGroup.UNITS_STABILITY, config);
@ -520,8 +543,8 @@ public class UnitGroup {
/** /**
* Return a UnitGroup for stability units based on a constant caliber. * Return a UnitGroup for stability units based on a constant caliber.
* *
* @param reference the constant reference length * @param reference the constant reference length
* @return the unit group * @return the unit group
*/ */
public static UnitGroup stabilityUnits(double reference) { public static UnitGroup stabilityUnits(double reference) {
return new StabilityUnitGroup(UnitGroup.UNITS_STABILITY, reference); return new StabilityUnitGroup(UnitGroup.UNITS_STABILITY, reference);
@ -577,8 +600,8 @@ public class UnitGroup {
* considered in the matching. This method is mainly means for testing, allowing * considered in the matching. This method is mainly means for testing, allowing
* a simple means to obtain a particular unit. * a simple means to obtain a particular unit.
* *
* @param str the unit name. * @param str the unit name.
* @return the corresponding unit, or <code>null</code> if not found. * @return the corresponding unit, or <code>null</code> if not found.
*/ */
public Unit findApproximate(String str) { public Unit findApproximate(String str) {
str = str.replaceAll("\\W", "").trim(); str = str.replaceAll("\\W", "").trim();
@ -594,8 +617,8 @@ public class UnitGroup {
* Set the default unit based on the unit name. Throws an exception if a * Set the default unit based on the unit name. Throws an exception if a
* unit with the provided name is not available. * unit with the provided name is not available.
* *
* @param name the unit name. * @param name the unit name.
* @throws IllegalArgumentException if the corresponding unit is not found in the group. * @throws IllegalArgumentException if the corresponding unit is not found in the group.
*/ */
public void setDefaultUnit(String name) throws IllegalArgumentException { public void setDefaultUnit(String name) throws IllegalArgumentException {
for (int i = 0; i < units.size(); i++) { for (int i = 0; i < units.size(); i++) {
@ -652,9 +675,9 @@ public class UnitGroup {
* Return the value formatted by the default unit of this group. * Return the value formatted by the default unit of this group.
* It is the same as calling <code>getDefaultUnit().toString(value)</code>. * It is the same as calling <code>getDefaultUnit().toString(value)</code>.
* *
* @param value the SI value to format. * @param value the SI value to format.
* @return the formatted string. * @return the formatted string.
* @see Unit#toString(double) * @see Unit#toString(double)
*/ */
public String toString(double value) { public String toString(double value) {
return this.getDefaultUnit().toString(value); return this.getDefaultUnit().toString(value);
@ -665,23 +688,20 @@ public class UnitGroup {
* Return the value formatted by the default unit of this group including the unit. * Return the value formatted by the default unit of this group including the unit.
* It is the same as calling <code>getDefaultUnit().toStringUnit(value)</code>. * It is the same as calling <code>getDefaultUnit().toStringUnit(value)</code>.
* *
* @param value the SI value to format. * @param value the SI value to format.
* @return the formatted string. * @return the formatted string.
* @see Unit#toStringUnit(double) * @see Unit#toStringUnit(double)
*/ */
public String toStringUnit(double value) { public String toStringUnit(double value) {
return this.getDefaultUnit().toStringUnit(value); return this.getDefaultUnit().toStringUnit(value);
} }
/** /**
* Creates a new Value object with the specified value and the default unit of this group. * Creates a new Value object with the specified value and the default unit of this group.
* *
* @param value the value to set. * @param value the value to set.
* @return a new Value object. * @return a new Value object.
*/ */
public Value toValue(double value) { public Value toValue(double value) {
return this.getDefaultUnit().toValue(value); return this.getDefaultUnit().toValue(value);
@ -723,7 +743,7 @@ public class UnitGroup {
* This method is applicable only for simple units without e.g. powers. * This method is applicable only for simple units without e.g. powers.
* *
* @param str the string to parse. * @param str the string to parse.
* @return the SI value. * @return the SI value.
* @throws NumberFormatException if the string cannot be parsed. * @throws NumberFormatException if the string cannot be parsed.
*/ */
public double fromString(String str) { public double fromString(String str) {

View File

@ -123,7 +123,8 @@ public class DoubleModel implements StateChangeListener, ChangeSource, Invalidat
@Override @Override
public Object getNextValue() { public Object getNextValue() {
double d = currentUnit.toUnit(DoubleModel.this.getValue()); double d = currentUnit.toUnit(DoubleModel.this.getValue());
double max = currentUnit.toUnit(maxValue); boolean inverted = DoubleModel.this.currentUnit.getMultiplier() < 0;
double max = inverted ? currentUnit.toUnit(minValue) : currentUnit.toUnit(maxValue);
if (MathUtil.equals(d, max)) if (MathUtil.equals(d, max))
return null; return null;
d = currentUnit.getNextValue(d); d = currentUnit.getNextValue(d);
@ -135,7 +136,8 @@ public class DoubleModel implements StateChangeListener, ChangeSource, Invalidat
@Override @Override
public Object getPreviousValue() { public Object getPreviousValue() {
double d = currentUnit.toUnit(DoubleModel.this.getValue()); double d = currentUnit.toUnit(DoubleModel.this.getValue());
double min = currentUnit.toUnit(minValue); boolean inverted = DoubleModel.this.currentUnit.getMultiplier() < 0;
double min = inverted ? currentUnit.toUnit(maxValue) : currentUnit.toUnit(minValue);
if (MathUtil.equals(d, min)) if (MathUtil.equals(d, min))
return null; return null;
d = currentUnit.getPreviousValue(d); d = currentUnit.getPreviousValue(d);
@ -315,10 +317,11 @@ public class DoubleModel implements StateChangeListener, ChangeSource, Invalidat
@Override @Override
public int getValue() { public int getValue() {
double value = DoubleModel.this.getValue(); double value = DoubleModel.this.getValue();
boolean inverted = DoubleModel.this.getCurrentUnit().getMultiplier() < 0;
if (value <= min.getValue()) if (value <= min.getValue())
return 0; return inverted ? MAX : 0;
if (value >= max.getValue()) if (value >= max.getValue())
return MAX; return inverted ? 0 : MAX;
double x; double x;
if ((value <= mid.getValue()) || (quad2 == 0)) { // If quad 2 is 0, the midpoint is perfectly in center if ((value <= mid.getValue()) || (quad2 == 0)) { // If quad 2 is 0, the midpoint is perfectly in center
@ -333,6 +336,9 @@ public class DoubleModel implements StateChangeListener, ChangeSource, Invalidat
// a*x^2 + b*x + c-value == 0 // a*x^2 + b*x + c-value == 0
x = (MathUtil.safeSqrt(quad1 * quad1 - 4 * quad2 * (quad0 - value)) - quad1) / (2 * quad2); x = (MathUtil.safeSqrt(quad1 * quad1 - 4 * quad2 * (quad0 - value)) - quad1) / (2 * quad2);
} }
if (inverted) {
x = 1 - x;
}
return (int) (x * MAX); return (int) (x * MAX);
} }
@ -346,7 +352,11 @@ public class DoubleModel implements StateChangeListener, ChangeSource, Invalidat
return; return;
} }
boolean inverted = DoubleModel.this.getCurrentUnit().getMultiplier() < 0;
double x = (double) newValue / MAX; double x = (double) newValue / MAX;
if (inverted) {
x = 1 - x;
}
double scaledValue; double scaledValue;
if (x <= linearPosition) { if (x <= linearPosition) {

View File

@ -160,6 +160,17 @@ public class UnitsPreferencesPanel extends PreferencesPanel {
combo = new JComboBox<Object>(new DefaultUnitSelector(UnitGroup.UNITS_WINDSPEED)); combo = new JComboBox<Object>(new DefaultUnitSelector(UnitGroup.UNITS_WINDSPEED));
rightPanel.add(combo, "sizegroup boxes, wrap"); rightPanel.add(combo, "sizegroup boxes, wrap");
//// Latitude
rightPanel.add(new JLabel(trans.get("pref.dlg.lbl.Latitude")));
combo = new JComboBox<>(new DefaultUnitSelector(UnitGroup.UNITS_LATITUDE));
rightPanel.add(combo, "sizegroup boxes, wrap");
//// Longitude
rightPanel.add(new JLabel(trans.get("pref.dlg.lbl.Longitude")));
combo = new JComboBox<>(new DefaultUnitSelector(UnitGroup.UNITS_LONGITUDE));
rightPanel.add(combo, "sizegroup boxes, wrap");
this.add(leftPanel, "top"); this.add(leftPanel, "top");
this.add(rightPanel, "top, wrap para"); this.add(rightPanel, "top, wrap para");

View File

@ -327,17 +327,17 @@ public class SimulationConditionsPanel extends JPanel {
label.setToolTipText(tip); label.setToolTipText(tip);
sub.add(label); sub.add(label);
m = new DoubleModel(target, "LaunchLatitude", UnitGroup.UNITS_NONE, -90, 90); m = new DoubleModel(target, "LaunchLatitude", UnitGroup.UNITS_LATITUDE, -90, 90);
spin = new JSpinner(m.getSpinnerModel()); spin = new JSpinner(m.getSpinnerModel());
spin.setEditor(new SpinnerEditor(spin)); spin.setEditor(new SpinnerEditor(spin));
spin.setToolTipText(tip); spin.setToolTipText(tip);
sub.add(spin, "w 65lp!"); sub.add(spin, "w 65lp!");
label = new JLabel(Chars.DEGREE + " N"); unit = new UnitSelector(m);
label.setToolTipText(tip); unit.setToolTipText(tip);
sub.add(label, "growx"); sub.add(unit, "growx");
slider = new BasicSlider(m.getSliderModel(-90, 90)); slider = new BasicSlider(m.getSliderModel());
slider.setToolTipText(tip); slider.setToolTipText(tip);
sub.add(slider, "w 75lp, wrap"); sub.add(slider, "w 75lp, wrap");
@ -348,17 +348,17 @@ public class SimulationConditionsPanel extends JPanel {
label.setToolTipText(tip); label.setToolTipText(tip);
sub.add(label); sub.add(label);
m = new DoubleModel(target, "LaunchLongitude", UnitGroup.UNITS_NONE, -180, 180); m = new DoubleModel(target, "LaunchLongitude", UnitGroup.UNITS_LONGITUDE, -180, 180);
spin = new JSpinner(m.getSpinnerModel()); spin = new JSpinner(m.getSpinnerModel());
spin.setEditor(new SpinnerEditor(spin)); spin.setEditor(new SpinnerEditor(spin));
spin.setToolTipText(tip); spin.setToolTipText(tip);
sub.add(spin, "w 65lp!"); sub.add(spin, "w 65lp!");
label = new JLabel(Chars.DEGREE + " E"); unit = new UnitSelector(m);
label.setToolTipText(tip); unit.setToolTipText(tip);
sub.add(label, "growx"); sub.add(unit, "growx");
slider = new BasicSlider(m.getSliderModel(-180, 180)); slider = new BasicSlider(m.getSliderModel());
slider.setToolTipText(tip); slider.setToolTipText(tip);
sub.add(slider, "w 75lp, wrap"); sub.add(slider, "w 75lp, wrap");