From: activityworkshop Date: Wed, 13 Jan 2021 17:54:09 +0000 (+0100) Subject: Project point to form a surrounding circle, for v21 X-Git-Tag: v21.dev.fp1~29 X-Git-Url: http://gitweb.fperrin.net/?p=GpsPrune.git;a=commitdiff_plain;h=c5f5c62d3ec5b267dd3b8e2e3b3e57790c7860af Project point to form a surrounding circle, for v21 --- diff --git a/src/tim/prune/FunctionLibrary.java b/src/tim/prune/FunctionLibrary.java index a1cb9ed..cb6001b 100644 --- a/src/tim/prune/FunctionLibrary.java +++ b/src/tim/prune/FunctionLibrary.java @@ -26,6 +26,7 @@ import tim.prune.function.IgnoreExifThumb; import tim.prune.function.InterpolateFunction; import tim.prune.function.PhotoPopupFunction; import tim.prune.function.PlayAudioFunction; +import tim.prune.function.ProjectCircle; import tim.prune.function.RearrangePhotosFunction; import tim.prune.function.RearrangeWaypointsFunction; import tim.prune.function.RemoveAudioFunction; @@ -86,6 +87,7 @@ public abstract class FunctionLibrary public static GenericFunction FUNCTION_SAVECONFIG = null; public static GenericFunction FUNCTION_EDIT_WAYPOINT_NAME = null; public static GenericFunction FUNCTION_PROJECT_POINT = null; + public static GenericFunction FUNCTION_PROJECT_CIRCLE = null; public static GenericFunction FUNCTION_REARRANGE_WAYPOINTS = null; public static GenericFunction FUNCTION_SELECT_SEGMENT = null; public static GenericFunction FUNCTION_SPLIT_SEGMENTS = null; @@ -163,6 +165,7 @@ public abstract class FunctionLibrary FUNCTION_SAVECONFIG = new SaveConfig(inApp); FUNCTION_EDIT_WAYPOINT_NAME = new PointNameEditor(inApp); FUNCTION_PROJECT_POINT = new ProjectPoint(inApp); + FUNCTION_PROJECT_CIRCLE = new ProjectCircle(inApp); FUNCTION_REARRANGE_WAYPOINTS = new RearrangeWaypointsFunction(inApp); FUNCTION_SELECT_SEGMENT = new SelectSegmentFunction(inApp); FUNCTION_SPLIT_SEGMENTS = new SplitSegmentsFunction(inApp); diff --git a/src/tim/prune/GpsPrune.java b/src/tim/prune/GpsPrune.java index 9eba28b..5503ccf 100644 --- a/src/tim/prune/GpsPrune.java +++ b/src/tim/prune/GpsPrune.java @@ -38,9 +38,9 @@ import tim.prune.gui.profile.ProfileChart; public class GpsPrune { /** Version number of application, used in about screen and for version check */ - public static final String VERSION_NUMBER = "20.2"; + public static final String VERSION_NUMBER = "21"; /** Build number, just used for about screen */ - public static final String BUILD_NUMBER = "383"; + public static final String BUILD_NUMBER = "384"; /** Static reference to App object */ private static App APP = null; diff --git a/src/tim/prune/function/ProjectCircle.java b/src/tim/prune/function/ProjectCircle.java new file mode 100644 index 0000000..bd33086 --- /dev/null +++ b/src/tim/prune/function/ProjectCircle.java @@ -0,0 +1,209 @@ +package tim.prune.function; + +import java.awt.BorderLayout; +import java.awt.Component; +import java.awt.FlowLayout; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; +import java.awt.event.KeyAdapter; +import java.awt.event.KeyEvent; +import java.awt.event.MouseAdapter; +import java.awt.event.MouseEvent; + +import javax.swing.BorderFactory; +import javax.swing.JButton; +import javax.swing.JDialog; +import javax.swing.JLabel; +import javax.swing.JPanel; +import javax.swing.SwingConstants; + +import tim.prune.App; +import tim.prune.GenericFunction; +import tim.prune.I18nManager; +import tim.prune.config.Config; +import tim.prune.data.DataPoint; +import tim.prune.data.Distance; +import tim.prune.data.Field; +import tim.prune.data.PointCreateOptions; +import tim.prune.data.SourceInfo; +import tim.prune.data.Unit; +import tim.prune.data.UnitSetLibrary; +import tim.prune.gui.DecimalNumberField; +import tim.prune.gui.GuiGridLayout; + + +/** + * Class to provide the function to project the current point + * to a circle at a given distance + */ +public class ProjectCircle extends GenericFunction +{ + private JDialog _dialog = null; + private JLabel _distanceDescLabel = null; + private DecimalNumberField _distanceField = null; + private boolean _distanceIsMetric = true; + private JButton _okButton = null; + + + /** + * Constructor + * @param inApp application object for callback + */ + public ProjectCircle(App inApp) + { + super(inApp); + } + + /** Get the name key */ + public String getNameKey() { + return "function.projectcircle"; + } + + /** + * Begin the function + */ + public void begin() + { + // Make dialog window + if (_dialog == null) + { + _dialog = new JDialog(_parentFrame, I18nManager.getText(getNameKey()), true); + _dialog.setLocationRelativeTo(_parentFrame); + _dialog.setDefaultCloseOperation(JDialog.DISPOSE_ON_CLOSE); + _dialog.getContentPane().add(makeDialogComponents()); + _dialog.pack(); + } + + // Clear fields + _distanceField.setText(""); + // Set the units of the distance label + setLabelText(); + enableOK(); + _dialog.setVisible(true); + } + + + /** + * Create dialog components + * @return Panel containing all gui elements in dialog + */ + private Component makeDialogComponents() + { + JPanel dialogPanel = new JPanel(); + dialogPanel.setLayout(new BorderLayout(0, 10)); + dialogPanel.add(new JLabel(I18nManager.getText("dialog.projectcircle.desc")), BorderLayout.NORTH); + JPanel mainPanel = new JPanel(); + GuiGridLayout grid = new GuiGridLayout(mainPanel); + _distanceField = new DecimalNumberField(false); + // Listeners to enable/disable ok button + KeyAdapter keyListener = new KeyAdapter() { + /** Key released */ + public void keyReleased(KeyEvent inE) { + enableOK(); + if (inE.getKeyCode() == KeyEvent.VK_ESCAPE) { + _dialog.dispose(); + } + } + }; + MouseAdapter mouseListener = new MouseAdapter() { + public void mouseReleased(MouseEvent inE) { + enableOK(); + } + }; + _distanceField.addKeyListener(keyListener); + _distanceField.addMouseListener(mouseListener); + + // Distance including units + _distanceDescLabel = new JLabel(I18nManager.getText("fieldname.distance") + " (ft)"); + // Note, this label will be reset at each run + _distanceDescLabel.setHorizontalAlignment(SwingConstants.RIGHT); + grid.add(_distanceDescLabel); + grid.add(_distanceField); + + dialogPanel.add(mainPanel, BorderLayout.CENTER); + // button panel at bottom + JPanel buttonPanel = new JPanel(); + buttonPanel.setLayout(new FlowLayout(FlowLayout.RIGHT)); + _okButton = new JButton(I18nManager.getText("button.ok")); + ActionListener okListener = new ActionListener() { + public void actionPerformed(ActionEvent e) + { + if (_okButton.isEnabled()) {finish();} + } + }; + _okButton.addActionListener(okListener); + _okButton.setEnabled(false); + + buttonPanel.add(_okButton); + JButton cancelButton = new JButton(I18nManager.getText("button.cancel")); + cancelButton.addActionListener(new ActionListener() { + public void actionPerformed(ActionEvent e) + { + _dialog.dispose(); + } + }); + buttonPanel.add(cancelButton); + dialogPanel.add(buttonPanel, BorderLayout.SOUTH); + dialogPanel.setBorder(BorderFactory.createEmptyBorder(10, 10, 10, 15)); + return dialogPanel; + } + + /** + * Set the label text according to the current units + */ + private void setLabelText() + { + Unit distUnit = Config.getUnitSet().getDistanceUnit(); + _distanceIsMetric = (distUnit == UnitSetLibrary.UNITS_METRES || distUnit == UnitSetLibrary.UNITS_KILOMETRES); + distUnit = _distanceIsMetric ? UnitSetLibrary.UNITS_METRES : UnitSetLibrary.UNITS_FEET; + final String unitKey = distUnit.getShortnameKey(); + _distanceDescLabel.setText(I18nManager.getText("fieldname.distance") + " (" + I18nManager.getText(unitKey) + ")"); + } + + /** + * Enable or disable the OK button based on the contents of the input fields + */ + private void enableOK() + { + final boolean distanceOk = _distanceField.getValue() > 0.0; + _okButton.setEnabled(distanceOk); + } + + /** + * Finish the dialog when OK pressed + */ + private void finish() + { + DataPoint currPoint = _app.getTrackInfo().getCurrentPoint(); + Unit distUnit = _distanceIsMetric ? UnitSetLibrary.UNITS_METRES : UnitSetLibrary.UNITS_FEET; + final double projectRads = Distance.convertDistanceToRadians(_distanceField.getValue(), distUnit); + final double origLatRads = Math.toRadians(currPoint.getLatitude().getDouble()); + final double origLonRads = Math.toRadians(currPoint.getLongitude().getDouble()); + System.out.println("Project from: " + origLatRads + ", " + origLonRads); + + final int NUM_POINTS_IN_CIRCLE = 24; + Object[][] dataArray = new Object[NUM_POINTS_IN_CIRCLE + 1][]; + for (int pointNum=0; pointNum<=NUM_POINTS_IN_CIRCLE; pointNum++) + { + final double bearingRads = (pointNum % NUM_POINTS_IN_CIRCLE) * 2.0 * Math.PI / NUM_POINTS_IN_CIRCLE; + + double lat2 = Math.asin(Math.sin(origLatRads) * Math.cos(projectRads) + + Math.cos(origLatRads) * Math.sin(projectRads) * Math.cos(bearingRads)); + double lon2 = origLonRads + Math.atan2(Math.sin(bearingRads) * Math.sin(projectRads) * Math.cos(origLatRads), + Math.cos(projectRads) - Math.sin(origLatRads) * Math.sin(lat2)); + + // Create point and append to track + dataArray[pointNum] = new String[2]; + dataArray[pointNum][0] = "" + Math.toDegrees(lat2); + dataArray[pointNum][1] = "" + Math.toDegrees(lon2); + } + + // give data to App + SourceInfo sourceInfo = null; + Field[] fieldArray = {Field.LATITUDE, Field.LONGITUDE}; + _app.autoAppendNextFile(); + _app.informDataLoaded(fieldArray, dataArray, new PointCreateOptions(), sourceInfo, null); + + _dialog.dispose(); + } +} diff --git a/src/tim/prune/gui/MenuManager.java b/src/tim/prune/gui/MenuManager.java index d87f459..a584815 100644 --- a/src/tim/prune/gui/MenuManager.java +++ b/src/tim/prune/gui/MenuManager.java @@ -79,6 +79,7 @@ public class MenuManager implements DataSubscriber private JMenuItem _findWaypointItem = null; private JMenuItem _duplicatePointItem = null; private JMenuItem _projectPointItem = null; + private JMenuItem _projectCircleItem = null; private JMenuItem _reverseItem = null; private JMenuItem _addTimeOffsetItem = null; private JMenuItem _addAltitudeOffsetItem = null; @@ -488,6 +489,9 @@ public class MenuManager implements DataSubscriber // project current point _projectPointItem = makeMenuItem(FunctionLibrary.FUNCTION_PROJECT_POINT, false); pointMenu.add(_projectPointItem); + _projectCircleItem = makeMenuItem(FunctionLibrary.FUNCTION_PROJECT_CIRCLE, false); + pointMenu.add(_projectCircleItem); + pointMenu.addSeparator(); // paste coordinates function JMenuItem pasteCoordsItem = makeMenuItem(new PasteCoordinates(_app)); pointMenu.add(pasteCoordsItem); @@ -913,6 +917,7 @@ public class MenuManager implements DataSubscriber _selectEndButton.setEnabled(hasPoint); _duplicatePointItem.setEnabled(hasPoint); _projectPointItem.setEnabled(hasPoint); + _projectCircleItem.setEnabled(hasPoint); _showPeakfinderItem.setEnabled(hasPoint); _showGeohackItem.setEnabled(hasPoint); _searchOpencachingDeItem.setEnabled(hasPoint); diff --git a/src/tim/prune/lang/prune-texts_de.properties b/src/tim/prune/lang/prune-texts_de.properties index ffc031d..7bf18b6 100644 --- a/src/tim/prune/lang/prune-texts_de.properties +++ b/src/tim/prune/lang/prune-texts_de.properties @@ -121,6 +121,7 @@ function.mapillary=Mapillary nach Fotos durchsuchen function.downloadosm=OSM-Daten f\u00fcr dieses Gebiet herunterladen function.duplicatepoint=Punkt verdoppeln function.projectpoint=Punkt projizieren +function.projectcircle=Kreis projizieren function.setcolours=Farben einstellen function.setdisplaysettings=Darstellungsoptionen function.setlanguage=Sprache einstellen diff --git a/src/tim/prune/lang/prune-texts_de_CH.properties b/src/tim/prune/lang/prune-texts_de_CH.properties index 555390e..1aa23e9 100644 --- a/src/tim/prune/lang/prune-texts_de_CH.properties +++ b/src/tim/prune/lang/prune-texts_de_CH.properties @@ -119,6 +119,7 @@ function.mapillary=Mapillary na F\u00f6telis durasueche function.downloadosm=OSM-Date f\u00fcr dere Gebiet abalad\u00e4 function.duplicatepoint=Punkt verdoppl\u00e4 function.projectpoint=Punkt projizier\u00e4 +function.projectcircle=Kreis projizier\u00e4 function.correlatephotos=F\u00f6telis korrelier\u00e4 function.rearrangephotos=F\u00f6telis reorganisier\u00e4 function.rotatephotoleft=F\u00f6teli nach Links dr\u00e4y\u00e4 diff --git a/src/tim/prune/lang/prune-texts_en.properties b/src/tim/prune/lang/prune-texts_en.properties index ad0d8db..922605c 100644 --- a/src/tim/prune/lang/prune-texts_en.properties +++ b/src/tim/prune/lang/prune-texts_en.properties @@ -121,6 +121,7 @@ function.mapillary=Search for photos in Mapillary function.downloadosm=Download OSM data for area function.duplicatepoint=Duplicate point function.projectpoint=Project point +function.projectcircle=Project circle around point function.connecttopoint=Connect to point function.disconnectfrompoint=Disconnect from point function.removephoto=Remove photo @@ -601,6 +602,7 @@ dialog.markers.half.climb=Half climb dialog.markers.half.descent=Half descent dialog.projectpoint.desc=Enter the direction and distance to project this point dialog.projectpoint.bearing=Bearing (degrees from N) +dialog.projectcircle.desc=Enter the distance from this point to the surrounding circle # 3d window dialog.3d.title=GpsPrune Three-d view