| 1 | // License: GPL. For details, see LICENSE file. |
| 2 | package org.openstreetmap.josm.plugins.photoadjust; |
| 3 | |
| 4 | import static org.openstreetmap.josm.tools.I18n.tr; |
| 5 | |
| 6 | import java.awt.event.ActionEvent; |
| 7 | import java.awt.geom.Point2D; |
| 8 | import java.util.Collections; |
| 9 | import java.util.List; |
| 10 | import java.util.Optional; |
| 11 | |
| 12 | import org.openstreetmap.josm.actions.JosmAction; |
| 13 | import org.openstreetmap.josm.data.ImageData; |
| 14 | import org.openstreetmap.josm.data.ImageData.ImageDataUpdateListener; |
| 15 | import org.openstreetmap.josm.data.coor.LatLon; |
| 16 | import org.openstreetmap.josm.gui.MainApplication; |
| 17 | import org.openstreetmap.josm.gui.MapView; |
| 18 | import org.openstreetmap.josm.gui.layer.Layer; |
| 19 | import org.openstreetmap.josm.gui.layer.LayerManager.LayerAddEvent; |
| 20 | import org.openstreetmap.josm.gui.layer.LayerManager.LayerChangeListener; |
| 21 | import org.openstreetmap.josm.gui.layer.LayerManager.LayerOrderChangeEvent; |
| 22 | import org.openstreetmap.josm.gui.layer.LayerManager.LayerRemoveEvent; |
| 23 | import org.openstreetmap.josm.gui.layer.geoimage.GeoImageLayer; |
| 24 | import org.openstreetmap.josm.gui.layer.geoimage.ImageEntry; |
| 25 | |
| 26 | /** |
| 27 | * Interpolate a part of a geotagged sequence |
| 28 | */ |
| 29 | public class InterpolateImages extends JosmAction implements LayerChangeListener, ImageDataUpdateListener { |
| 30 | |
| 31 | public InterpolateImages() { |
| 32 | super(tr("Interpolate position between the 2 images"), |
| 33 | null, |
| 34 | tr("Interpolate images position between the 2 selected images"), |
| 35 | null, false, false); |
| 36 | |
| 37 | installAdapters(); |
| 38 | updateEnabledState(); |
| 39 | } |
| 40 | |
| 41 | @Override |
| 42 | public void actionPerformed(ActionEvent evt) { |
| 43 | if (!getLayerWithTwoSelectedImages().isPresent()) { |
| 44 | return; |
| 45 | } |
| 46 | GeoImageLayer layer = getLayerWithTwoSelectedImages().get(); |
| 47 | ImageData data = layer.getImageData(); |
| 48 | |
| 49 | interpolate(data, MainApplication.getMap().mapView); |
| 50 | } |
| 51 | |
| 52 | public void interpolate(ImageData data, MapView mapView) { |
| 53 | List<ImageEntry> images = data.getImages(); |
| 54 | List<ImageEntry> selectedImages = data.getSelectedImages(); |
| 55 | Collections.sort(selectedImages); |
| 56 | ImageEntry firstPhoto = selectedImages.get(0); |
| 57 | ImageEntry lastPhoto = selectedImages.get(1); |
| 58 | final Point2D firstPos = mapView.getPoint2D(firstPhoto.getPos()); |
| 59 | final Point2D lastPos = mapView.getPoint2D(lastPhoto.getPos()); |
| 60 | int nbSegments = images.indexOf(lastPhoto) - images.indexOf(firstPhoto); |
| 61 | double firstPosX = firstPos.getX(); |
| 62 | double firstPosY = firstPos.getY(); |
| 63 | double offsetX = (lastPos.getX() - firstPosX) / nbSegments; |
| 64 | double offsetY = (lastPos.getY() - firstPosY) / nbSegments; |
| 65 | int firstIndex = images.indexOf(firstPhoto); |
| 66 | for (int idx = 1; idx < nbSegments; idx++) { |
| 67 | ImageEntry image = images.get(firstIndex + idx); |
| 68 | LatLon newPos = mapView.getLatLon( |
| 69 | firstPosX + offsetX * idx, |
| 70 | firstPosY + offsetY * idx |
| 71 | ); |
| 72 | image.setPos(newPos); |
| 73 | image.flagNewGpsData(); |
| 74 | } |
| 75 | data.notifyImageUpdate(); |
| 76 | } |
| 77 | |
| 78 | @Override |
| 79 | protected void installAdapters() { |
| 80 | MainApplication.getLayerManager().addLayerChangeListener(this); |
| 81 | } |
| 82 | |
| 83 | @Override |
| 84 | protected void updateEnabledState() { |
| 85 | setEnabled(getLayerWithTwoSelectedImages().isPresent()); |
| 86 | } |
| 87 | |
| 88 | private static Optional<GeoImageLayer> getLayerWithTwoSelectedImages() { |
| 89 | List<GeoImageLayer> list = MainApplication.getLayerManager().getLayersOfType(GeoImageLayer.class); |
| 90 | return list.stream().filter(l -> l.getImageData().getSelectedImages().size() == 2).findFirst(); |
| 91 | } |
| 92 | |
| 93 | @Override |
| 94 | public void layerAdded(LayerAddEvent evt) { |
| 95 | Layer layer = evt.getAddedLayer(); |
| 96 | if (layer instanceof GeoImageLayer) { |
| 97 | ((GeoImageLayer) layer).getImageData().addImageDataUpdateListener(this); |
| 98 | } |
| 99 | } |
| 100 | |
| 101 | @Override |
| 102 | public void layerRemoving(LayerRemoveEvent evt) { |
| 103 | Layer layer = evt.getRemovedLayer(); |
| 104 | |
| 105 | if (layer instanceof GeoImageLayer) { |
| 106 | ((GeoImageLayer) layer).getImageData().removeImageDataUpdateListener(this); |
| 107 | } |
| 108 | updateEnabledState(); |
| 109 | } |
| 110 | |
| 111 | @Override |
| 112 | public void layerOrderChanged(LayerOrderChangeEvent evt) {} |
| 113 | |
| 114 | @Override |
| 115 | public void imageDataUpdated(ImageData data) {} |
| 116 | |
| 117 | @Override |
| 118 | public void selectedImageChanged(ImageData data) { |
| 119 | updateEnabledState(); |
| 120 | } |
| 121 | } |