]> gitweb.fperrin.net Git - GpsPrune.git/blob - src/tim/prune/function/ProjectCircle.java
Project point to form a surrounding circle, for v21
[GpsPrune.git] / src / tim / prune / function / ProjectCircle.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.SwingConstants;
19
20 import tim.prune.App;
21 import tim.prune.GenericFunction;
22 import tim.prune.I18nManager;
23 import tim.prune.config.Config;
24 import tim.prune.data.DataPoint;
25 import tim.prune.data.Distance;
26 import tim.prune.data.Field;
27 import tim.prune.data.PointCreateOptions;
28 import tim.prune.data.SourceInfo;
29 import tim.prune.data.Unit;
30 import tim.prune.data.UnitSetLibrary;
31 import tim.prune.gui.DecimalNumberField;
32 import tim.prune.gui.GuiGridLayout;
33
34
35 /**
36  * Class to provide the function to project the current point
37  * to a circle at a given distance
38  */
39 public class ProjectCircle extends GenericFunction
40 {
41         private JDialog _dialog = null;
42         private JLabel _distanceDescLabel = null;
43         private DecimalNumberField _distanceField = null;
44         private boolean _distanceIsMetric = true;
45         private JButton _okButton = null;
46
47
48         /**
49          * Constructor
50          * @param inApp application object for callback
51          */
52         public ProjectCircle(App inApp)
53         {
54                 super(inApp);
55         }
56
57         /** Get the name key */
58         public String getNameKey() {
59                 return "function.projectcircle";
60         }
61
62         /**
63          * Begin the function
64          */
65         public void begin()
66         {
67                 // Make dialog window
68                 if (_dialog == null)
69                 {
70                         _dialog = new JDialog(_parentFrame, I18nManager.getText(getNameKey()), true);
71                         _dialog.setLocationRelativeTo(_parentFrame);
72                         _dialog.setDefaultCloseOperation(JDialog.DISPOSE_ON_CLOSE);
73                         _dialog.getContentPane().add(makeDialogComponents());
74                         _dialog.pack();
75                 }
76
77                 // Clear fields
78                 _distanceField.setText("");
79                 // Set the units of the distance label
80                 setLabelText();
81                 enableOK();
82                 _dialog.setVisible(true);
83         }
84
85
86         /**
87          * Create dialog components
88          * @return Panel containing all gui elements in dialog
89          */
90         private Component makeDialogComponents()
91         {
92                 JPanel dialogPanel = new JPanel();
93                 dialogPanel.setLayout(new BorderLayout(0, 10));
94                 dialogPanel.add(new JLabel(I18nManager.getText("dialog.projectcircle.desc")), BorderLayout.NORTH);
95                 JPanel mainPanel = new JPanel();
96                 GuiGridLayout grid = new GuiGridLayout(mainPanel);
97                 _distanceField = new DecimalNumberField(false);
98                 // Listeners to enable/disable ok button
99                 KeyAdapter keyListener = new KeyAdapter() {
100                         /** Key released */
101                         public void keyReleased(KeyEvent inE) {
102                                 enableOK();
103                                 if (inE.getKeyCode() == KeyEvent.VK_ESCAPE) {
104                                         _dialog.dispose();
105                                 }
106                         }
107                 };
108                 MouseAdapter mouseListener = new MouseAdapter() {
109                         public void mouseReleased(MouseEvent inE) {
110                                 enableOK();
111                         }
112                 };
113                 _distanceField.addKeyListener(keyListener);
114                 _distanceField.addMouseListener(mouseListener);
115
116                 // Distance including units
117                 _distanceDescLabel = new JLabel(I18nManager.getText("fieldname.distance") + " (ft)");
118                 // Note, this label will be reset at each run
119                 _distanceDescLabel.setHorizontalAlignment(SwingConstants.RIGHT);
120                 grid.add(_distanceDescLabel);
121                 grid.add(_distanceField);
122
123                 dialogPanel.add(mainPanel, BorderLayout.CENTER);
124                 // button panel at bottom
125                 JPanel buttonPanel = new JPanel();
126                 buttonPanel.setLayout(new FlowLayout(FlowLayout.RIGHT));
127                 _okButton = new JButton(I18nManager.getText("button.ok"));
128                 ActionListener okListener = new ActionListener() {
129                         public void actionPerformed(ActionEvent e)
130                         {
131                                 if (_okButton.isEnabled()) {finish();}
132                         }
133                 };
134                 _okButton.addActionListener(okListener);
135                 _okButton.setEnabled(false);
136
137                 buttonPanel.add(_okButton);
138                 JButton cancelButton = new JButton(I18nManager.getText("button.cancel"));
139                 cancelButton.addActionListener(new ActionListener() {
140                         public void actionPerformed(ActionEvent e)
141                         {
142                                 _dialog.dispose();
143                         }
144                 });
145                 buttonPanel.add(cancelButton);
146                 dialogPanel.add(buttonPanel, BorderLayout.SOUTH);
147                 dialogPanel.setBorder(BorderFactory.createEmptyBorder(10, 10, 10, 15));
148                 return dialogPanel;
149         }
150
151         /**
152          * Set the label text according to the current units
153          */
154         private void setLabelText()
155         {
156                 Unit distUnit = Config.getUnitSet().getDistanceUnit();
157                 _distanceIsMetric = (distUnit == UnitSetLibrary.UNITS_METRES || distUnit == UnitSetLibrary.UNITS_KILOMETRES);
158                 distUnit = _distanceIsMetric ? UnitSetLibrary.UNITS_METRES : UnitSetLibrary.UNITS_FEET;
159                 final String unitKey = distUnit.getShortnameKey();
160                 _distanceDescLabel.setText(I18nManager.getText("fieldname.distance") + " (" + I18nManager.getText(unitKey) + ")");
161         }
162
163         /**
164          * Enable or disable the OK button based on the contents of the input fields
165          */
166         private void enableOK()
167         {
168                 final boolean distanceOk = _distanceField.getValue() > 0.0;
169                 _okButton.setEnabled(distanceOk);
170         }
171
172         /**
173          * Finish the dialog when OK pressed
174          */
175         private void finish()
176         {
177                 DataPoint currPoint = _app.getTrackInfo().getCurrentPoint();
178                 Unit distUnit = _distanceIsMetric ? UnitSetLibrary.UNITS_METRES : UnitSetLibrary.UNITS_FEET;
179                 final double projectRads = Distance.convertDistanceToRadians(_distanceField.getValue(), distUnit);
180                 final double origLatRads = Math.toRadians(currPoint.getLatitude().getDouble());
181                 final double origLonRads = Math.toRadians(currPoint.getLongitude().getDouble());
182                 System.out.println("Project from: " + origLatRads + ", " + origLonRads);
183
184                 final int NUM_POINTS_IN_CIRCLE = 24;
185                 Object[][] dataArray = new Object[NUM_POINTS_IN_CIRCLE + 1][];
186                 for (int pointNum=0; pointNum<=NUM_POINTS_IN_CIRCLE; pointNum++)
187                 {
188                         final double bearingRads = (pointNum % NUM_POINTS_IN_CIRCLE) * 2.0 * Math.PI / NUM_POINTS_IN_CIRCLE;
189
190                         double lat2 = Math.asin(Math.sin(origLatRads) * Math.cos(projectRads)
191                                 + Math.cos(origLatRads) * Math.sin(projectRads) * Math.cos(bearingRads));
192                         double lon2 = origLonRads + Math.atan2(Math.sin(bearingRads) * Math.sin(projectRads) * Math.cos(origLatRads),
193                                 Math.cos(projectRads) - Math.sin(origLatRads) * Math.sin(lat2));
194
195                         // Create point and append to track
196                         dataArray[pointNum] = new String[2];
197                         dataArray[pointNum][0] = "" + Math.toDegrees(lat2);
198                         dataArray[pointNum][1] = "" + Math.toDegrees(lon2);
199                 }
200
201                 // give data to App
202                 SourceInfo sourceInfo = null;
203                 Field[] fieldArray = {Field.LATITUDE, Field.LONGITUDE};
204                 _app.autoAppendNextFile();
205                 _app.informDataLoaded(fieldArray, dataArray, new PointCreateOptions(), sourceInfo, null);
206
207                 _dialog.dispose();
208         }
209 }