1 package tim.prune.function;
3 import java.awt.BorderLayout;
4 import java.awt.Component;
5 import java.awt.FlowLayout;
6 import java.awt.event.ActionEvent;
7 import java.awt.event.ActionListener;
8 import java.awt.event.KeyAdapter;
9 import java.awt.event.KeyEvent;
10 import java.awt.event.MouseAdapter;
11 import java.awt.event.MouseEvent;
13 import javax.swing.BorderFactory;
14 import javax.swing.JButton;
15 import javax.swing.JDialog;
16 import javax.swing.JLabel;
17 import javax.swing.JPanel;
18 import javax.swing.JTextField;
19 import javax.swing.SwingConstants;
22 import tim.prune.GenericFunction;
23 import tim.prune.I18nManager;
24 import tim.prune.config.Config;
25 import tim.prune.data.Coordinate;
26 import tim.prune.data.DataPoint;
27 import tim.prune.data.Distance;
28 import tim.prune.data.Field;
29 import tim.prune.data.Latitude;
30 import tim.prune.data.Longitude;
31 import tim.prune.data.Unit;
32 import tim.prune.data.UnitSetLibrary;
33 import tim.prune.gui.DecimalNumberField;
34 import tim.prune.gui.GuiGridLayout;
35 import tim.prune.gui.WholeNumberField;
39 * Class to provide the function to project the current point
40 * with a given bearing and distance
42 public class ProjectPoint extends GenericFunction
44 private JDialog _dialog = null;
45 private WholeNumberField _bearingField = null;
46 private JLabel _distanceDescLabel = null;
47 private DecimalNumberField _distanceField = null;
48 private boolean _distanceIsMetric = true;
49 private JTextField _nameField = null;
50 private JButton _okButton = null;
55 * @param inApp application object for callback
57 public ProjectPoint(App inApp)
62 /** Get the name key */
63 public String getNameKey() {
64 return "function.projectpoint";
75 _dialog = new JDialog(_parentFrame, I18nManager.getText(getNameKey()), true);
76 _dialog.setLocationRelativeTo(_parentFrame);
77 _dialog.setDefaultCloseOperation(JDialog.DISPOSE_ON_CLOSE);
78 _dialog.getContentPane().add(makeDialogComponents());
83 _bearingField.setText("");
84 _distanceField.setText("");
85 _nameField.setText("");
86 // Set the units of the distance label
89 _dialog.setVisible(true);
94 * Create dialog components
95 * @return Panel containing all gui elements in dialog
97 private Component makeDialogComponents()
99 JPanel dialogPanel = new JPanel();
100 dialogPanel.setLayout(new BorderLayout(0, 10));
101 dialogPanel.add(new JLabel(I18nManager.getText("dialog.projectpoint.desc")), BorderLayout.NORTH);
102 JPanel mainPanel = new JPanel();
103 GuiGridLayout grid = new GuiGridLayout(mainPanel);
104 _bearingField = new WholeNumberField(3);
105 _distanceField = new DecimalNumberField(false);
106 // Listeners to enable/disable ok button
107 KeyAdapter keyListener = new KeyAdapter() {
109 public void keyReleased(KeyEvent inE) {
111 if (inE.getKeyCode() == KeyEvent.VK_ESCAPE) {
116 MouseAdapter mouseListener = new MouseAdapter() {
117 public void mouseReleased(MouseEvent inE) {
121 _bearingField.addKeyListener(keyListener);
122 _bearingField.addMouseListener(mouseListener);
123 _distanceField.addKeyListener(keyListener);
124 _distanceField.addMouseListener(mouseListener);
126 JLabel bearingLabel = new JLabel(I18nManager.getText("dialog.projectpoint.bearing"));
127 bearingLabel.setHorizontalAlignment(SwingConstants.RIGHT);
128 grid.add(bearingLabel);
129 grid.add(_bearingField);
131 // Distance including units
132 _distanceDescLabel = new JLabel(I18nManager.getText("fieldname.distance") + " (ft)");
133 // Note, this label will be reset at each run
134 _distanceDescLabel.setHorizontalAlignment(SwingConstants.RIGHT);
135 grid.add(_distanceDescLabel);
136 grid.add(_distanceField);
139 JLabel nameLabel = new JLabel(I18nManager.getText("dialog.pointnameedit.name"));
140 nameLabel.setHorizontalAlignment(SwingConstants.RIGHT);
142 _nameField = new JTextField("", 12);
143 grid.add(_nameField);
144 dialogPanel.add(mainPanel, BorderLayout.CENTER);
145 // button panel at bottom
146 JPanel buttonPanel = new JPanel();
147 buttonPanel.setLayout(new FlowLayout(FlowLayout.RIGHT));
148 _okButton = new JButton(I18nManager.getText("button.ok"));
149 ActionListener okListener = new ActionListener() {
150 public void actionPerformed(ActionEvent e)
152 if (_okButton.isEnabled()) {finish();}
155 _okButton.addActionListener(okListener);
156 _okButton.setEnabled(false);
158 buttonPanel.add(_okButton);
159 JButton cancelButton = new JButton(I18nManager.getText("button.cancel"));
160 cancelButton.addActionListener(new ActionListener() {
161 public void actionPerformed(ActionEvent e)
166 buttonPanel.add(cancelButton);
167 dialogPanel.add(buttonPanel, BorderLayout.SOUTH);
168 dialogPanel.setBorder(BorderFactory.createEmptyBorder(10, 10, 10, 15));
173 * Set the label text according to the current units
175 private void setLabelText()
177 Unit distUnit = Config.getUnitSet().getDistanceUnit();
178 _distanceIsMetric = (distUnit == UnitSetLibrary.UNITS_METRES || distUnit == UnitSetLibrary.UNITS_KILOMETRES);
179 distUnit = _distanceIsMetric ? UnitSetLibrary.UNITS_METRES : UnitSetLibrary.UNITS_FEET;
180 final String unitKey = distUnit.getShortnameKey();
181 _distanceDescLabel.setText(I18nManager.getText("fieldname.distance") + " (" + I18nManager.getText(unitKey) + ")");
185 * Enable or disable the OK button based on the contents of the input fields
187 private void enableOK()
189 final boolean bearingOk = !_bearingField.getText().isEmpty()
190 && _bearingField.getValue() < 360;
191 final boolean distanceOk = _distanceField.getValue() > 0.0;
192 _okButton.setEnabled(bearingOk && distanceOk);
196 * Finish the dialog when OK pressed
198 private void finish()
200 DataPoint currPoint = _app.getTrackInfo().getCurrentPoint();
201 Unit distUnit = _distanceIsMetric ? UnitSetLibrary.UNITS_METRES : UnitSetLibrary.UNITS_FEET;
202 final double projectRads = Distance.convertDistanceToRadians(_distanceField.getValue(), distUnit);
203 final double origLatRads = Math.toRadians(currPoint.getLatitude().getDouble());
204 final double origLonRads = Math.toRadians(currPoint.getLongitude().getDouble());
205 final double bearingRads = Math.toRadians(_bearingField.getValue());
207 double lat2 = Math.asin(Math.sin(origLatRads) * Math.cos(projectRads)
208 + Math.cos(origLatRads) * Math.sin(projectRads) * Math.cos(bearingRads));
209 double lon2 = origLonRads + Math.atan2(Math.sin(bearingRads) * Math.sin(projectRads) * Math.cos(origLatRads),
210 Math.cos(projectRads) - Math.sin(origLatRads) * Math.sin(lat2));
212 double finalLatDeg = Math.toDegrees(lat2);
213 double finalLonDeg = Math.toDegrees(lon2);
215 // Create point and append to track
216 DataPoint point = new DataPoint(new Latitude(finalLatDeg, Coordinate.FORMAT_DEG),
217 new Longitude(finalLonDeg, Coordinate.FORMAT_DEG), null);
218 point.setFieldValue(Field.WAYPT_NAME, _nameField.getText(), false);
219 _app.createPoint(point);