]> gitweb.fperrin.net Git - GpsPrune.git/blob - src/tim/prune/function/ProjectPoint.java
Version 20.4, May 2021
[GpsPrune.git] / src / tim / prune / function / ProjectPoint.java
1 package tim.prune.function;
2
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;
12
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;
20
21 import tim.prune.App;
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;
36
37
38 /**
39  * Class to provide the function to project the current point
40  * with a given bearing and distance
41  */
42 public class ProjectPoint extends GenericFunction
43 {
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;
51
52
53         /**
54          * Constructor
55          * @param inApp application object for callback
56          */
57         public ProjectPoint(App inApp)
58         {
59                 super(inApp);
60         }
61
62         /** Get the name key */
63         public String getNameKey() {
64                 return "function.projectpoint";
65         }
66
67         /**
68          * Begin the function
69          */
70         public void begin()
71         {
72                 // Make dialog window
73                 if (_dialog == null)
74                 {
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());
79                         _dialog.pack();
80                 }
81
82                 // Clear fields
83                 _bearingField.setText("");
84                 _distanceField.setText("");
85                 _nameField.setText("");
86                 // Set the units of the distance label
87                 setLabelText();
88                 enableOK();
89                 _dialog.setVisible(true);
90         }
91
92
93         /**
94          * Create dialog components
95          * @return Panel containing all gui elements in dialog
96          */
97         private Component makeDialogComponents()
98         {
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() {
108                         /** Key released */
109                         public void keyReleased(KeyEvent inE) {
110                                 enableOK();
111                                 if (inE.getKeyCode() == KeyEvent.VK_ESCAPE) {
112                                         _dialog.dispose();
113                                 }
114                         }
115                 };
116                 MouseAdapter mouseListener = new MouseAdapter() {
117                         public void mouseReleased(MouseEvent inE) {
118                                 enableOK();
119                         }
120                 };
121                 _bearingField.addKeyListener(keyListener);
122                 _bearingField.addMouseListener(mouseListener);
123                 _distanceField.addKeyListener(keyListener);
124                 _distanceField.addMouseListener(mouseListener);
125
126                 JLabel bearingLabel = new JLabel(I18nManager.getText("dialog.projectpoint.bearing"));
127                 bearingLabel.setHorizontalAlignment(SwingConstants.RIGHT);
128                 grid.add(bearingLabel);
129                 grid.add(_bearingField);
130
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);
137
138                 // Waypoint name
139                 JLabel nameLabel = new JLabel(I18nManager.getText("dialog.pointnameedit.name"));
140                 nameLabel.setHorizontalAlignment(SwingConstants.RIGHT);
141                 grid.add(nameLabel);
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)
151                         {
152                                 if (_okButton.isEnabled()) {finish();}
153                         }
154                 };
155                 _okButton.addActionListener(okListener);
156                 _okButton.setEnabled(false);
157
158                 buttonPanel.add(_okButton);
159                 JButton cancelButton = new JButton(I18nManager.getText("button.cancel"));
160                 cancelButton.addActionListener(new ActionListener() {
161                         public void actionPerformed(ActionEvent e)
162                         {
163                                 _dialog.dispose();
164                         }
165                 });
166                 buttonPanel.add(cancelButton);
167                 dialogPanel.add(buttonPanel, BorderLayout.SOUTH);
168                 dialogPanel.setBorder(BorderFactory.createEmptyBorder(10, 10, 10, 15));
169                 return dialogPanel;
170         }
171
172         /**
173          * Set the label text according to the current units
174          */
175         private void setLabelText()
176         {
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) + ")");
182         }
183
184         /**
185          * Enable or disable the OK button based on the contents of the input fields
186          */
187         private void enableOK()
188         {
189                 final boolean bearingOk = !_bearingField.getText().isEmpty()
190                         && _bearingField.getValue() < 360;
191                 final boolean distanceOk = _distanceField.getValue() > 0.0;
192                 _okButton.setEnabled(bearingOk && distanceOk);
193         }
194
195         /**
196          * Finish the dialog when OK pressed
197          */
198         private void finish()
199         {
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                 System.out.println("Project from: " + origLatRads + ", " + origLonRads);
206                 final double bearingRads = Math.toRadians(_bearingField.getValue());
207
208                 double lat2 = Math.asin(Math.sin(origLatRads) * Math.cos(projectRads)
209                         + Math.cos(origLatRads) * Math.sin(projectRads) * Math.cos(bearingRads));
210                 double lon2 = origLonRads + Math.atan2(Math.sin(bearingRads) * Math.sin(projectRads) * Math.cos(origLatRads),
211                         Math.cos(projectRads) - Math.sin(origLatRads) * Math.sin(lat2));
212
213                 double finalLatDeg = Math.toDegrees(lat2);
214                 double finalLonDeg = Math.toDegrees(lon2);
215                 System.out.println("Result is: lat=" + finalLatDeg + ", lon=" + finalLonDeg);
216
217                 // Create point and append to track
218                 DataPoint point = new DataPoint(new Latitude(finalLatDeg, Coordinate.FORMAT_DEG),
219                         new Longitude(finalLonDeg, Coordinate.FORMAT_DEG), null);
220                 point.setFieldValue(Field.WAYPT_NAME, _nameField.getText(), false);
221                 _app.createPoint(point);
222
223                 _dialog.dispose();
224         }
225 }