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.SwingConstants;
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;
36 * Class to provide the function to project the current point
37 * to a circle at a given distance
39 public class ProjectCircle extends GenericFunction
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;
50 * @param inApp application object for callback
52 public ProjectCircle(App inApp)
57 /** Get the name key */
58 public String getNameKey() {
59 return "function.projectcircle";
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());
78 _distanceField.setText("");
79 // Set the units of the distance label
82 _dialog.setVisible(true);
87 * Create dialog components
88 * @return Panel containing all gui elements in dialog
90 private Component makeDialogComponents()
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() {
101 public void keyReleased(KeyEvent inE) {
103 if (inE.getKeyCode() == KeyEvent.VK_ESCAPE) {
108 MouseAdapter mouseListener = new MouseAdapter() {
109 public void mouseReleased(MouseEvent inE) {
113 _distanceField.addKeyListener(keyListener);
114 _distanceField.addMouseListener(mouseListener);
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);
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)
131 if (_okButton.isEnabled()) {finish();}
134 _okButton.addActionListener(okListener);
135 _okButton.setEnabled(false);
137 buttonPanel.add(_okButton);
138 JButton cancelButton = new JButton(I18nManager.getText("button.cancel"));
139 cancelButton.addActionListener(new ActionListener() {
140 public void actionPerformed(ActionEvent e)
145 buttonPanel.add(cancelButton);
146 dialogPanel.add(buttonPanel, BorderLayout.SOUTH);
147 dialogPanel.setBorder(BorderFactory.createEmptyBorder(10, 10, 10, 15));
152 * Set the label text according to the current units
154 private void setLabelText()
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) + ")");
164 * Enable or disable the OK button based on the contents of the input fields
166 private void enableOK()
168 final boolean distanceOk = _distanceField.getValue() > 0.0;
169 _okButton.setEnabled(distanceOk);
173 * Finish the dialog when OK pressed
175 private void finish()
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);
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++)
188 final double bearingRads = (pointNum % NUM_POINTS_IN_CIRCLE) * 2.0 * Math.PI / NUM_POINTS_IN_CIRCLE;
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));
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);
202 SourceInfo sourceInfo = null;
203 Field[] fieldArray = {Field.LATITUDE, Field.LONGITUDE};
204 _app.autoAppendNextFile();
205 _app.informDataLoaded(fieldArray, dataArray, new PointCreateOptions(), sourceInfo, null);