| | 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 | } |