package org.openstreetmap.josm.plugins.photoadjust; import java.awt.event.InputEvent; import java.awt.event.MouseEvent; import java.awt.geom.Point2D; import java.util.List; import org.openstreetmap.josm.Main; import org.openstreetmap.josm.data.coor.LatLon; import org.openstreetmap.josm.gui.layer.geoimage.GeoImageLayer; import org.openstreetmap.josm.gui.layer.geoimage.ImageEntry; import org.openstreetmap.josm.gui.layer.geoimage.ImageViewerDialog; /** * Class that does the actual work. */ public class PhotoAdjustWorker { private ImageEntry dragPhoto = null; private GeoImageLayer dragLayer = null; // Offset between center of the photo and point where it is // clicked. This must be in pixels to maintain the same offset if // the photo is moved very far. private Point2D dragOffset = null; private boolean centerViewIsDisabled = false; private boolean centerViewNeedsEnable = false; /** * Reset the worker. */ public void reset() { dragPhoto = null; dragLayer = null; dragOffset = null; } /** * Disable the "center view" button. The map is moved instead of the * photo if the center view is enabled while a photo is moved. The method * disables the center view to avoid such behavior. Call * restoreCenterView() to restore the original state. */ public synchronized void disableCenterView() { if (!centerViewIsDisabled && ImageViewerDialog.isCenterView()) { centerViewIsDisabled = true; centerViewNeedsEnable = ImageViewerDialog.setCentreEnabled(false); } } /** * Restore the center view state that was active before * disableCenterView() was called. */ public synchronized void restoreCenterView() { if (centerViewIsDisabled) { if (centerViewNeedsEnable) { centerViewNeedsEnable = false; ImageViewerDialog.setCentreEnabled(true); } centerViewIsDisabled = false; } } /** * Mouse click handler. Control+click changes the image direction if * there is a photo selected on the map. Shift+click positions the photo * from the ImageViewerDialog. Click without shift or control checks if * there is a photo under the mouse. * * @param evt Mouse event from MouseAdapter mousePressed(). * @param imageLayers List of GeoImageLayers to be considered. */ public void doMousePressed(MouseEvent evt, List<GeoImageLayer> imageLayers) { reset(); if (evt.getButton() == MouseEvent.BUTTON1 && imageLayers != null && imageLayers.size() > 0) { // Check if modifier key is pressed and change to // image viewer photo if it is. final boolean isShift = (evt.getModifiers() & InputEvent.SHIFT_MASK) != 0; final boolean isCtrl = (evt.getModifiers() & InputEvent.CTRL_MASK) != 0; if (isShift || isCtrl) { final GeoImageLayer viewerLayer = ImageViewerDialog.getCurrentLayer(); final ImageEntry img = ImageViewerDialog.getCurrentImage(); if ( img != null && viewerLayer != null && viewerLayer.isVisible() && imageLayers.contains(viewerLayer)) { // Change direction if control is pressed, position // otherwise. Shift+control changes direction, similar to // rotate in select mode. // // Combinations: // S ... shift pressed // C ... control pressed // pos ... photo has a position set == is displayed on the map // nopos ... photo has no position set // // S + pos: position at mouse // S + nopos: position at mouse // C + pos: change orientation // C + nopos: ignored // S + C + pos: change orientation // S + C + nopos: ignore if (isCtrl) { if (img.getPos() != null) { changeDirection(img, viewerLayer, evt); } } else { // shift pressed movePhoto(img, viewerLayer, evt); } dragPhoto = img; dragLayer = viewerLayer; } } else { // Start with the top layer. for (GeoImageLayer layer: imageLayers) { if (layer.isVisible()) { dragPhoto = layer.getPhotoUnderMouse(evt); if (dragPhoto != null) { dragLayer = layer; setDragOffset(dragPhoto, evt); disableCenterView(); break; } } } } } } /** * Mouse release handler. * * @param evt Mouse event from MouseAdapter mouseReleased(). */ public void doMouseReleased(MouseEvent evt) { restoreCenterView(); } /** * Mouse drag handler. Changes direction or moves photo. * * @param evt Mouse event from MouseMotionAdapter mouseDragged(). */ public void doMouseDragged(MouseEvent evt) { if ( dragLayer != null && dragLayer.isVisible() && dragPhoto != null) { if ((evt.getModifiers() & InputEvent.CTRL_MASK) != 0) { changeDirection(dragPhoto, dragLayer, evt); } else { disableCenterView(); movePhoto(dragPhoto, dragLayer, evt); } } } /** * Set the offset between a photo and the current mouse position. * * @param photo The photo to move. * @param evt Mouse event from one of the mouse adapters. */ private void setDragOffset(ImageEntry photo, MouseEvent evt) { final Point2D centerPoint = Main.map.mapView.getPoint2D(photo.getPos()); dragOffset = new Point2D.Double(centerPoint.getX() - evt.getX(), centerPoint.getY() - evt.getY()); } /** * Move the photo to the mouse position. * * @param photo The photo to move. * @param layer GeoImageLayer of the photo. * @param evt Mouse event from one of the mouse adapters. */ private void movePhoto(ImageEntry photo, GeoImageLayer layer, MouseEvent evt) { LatLon newPos; if (dragOffset != null) { newPos = Main.map.mapView.getLatLon(dragOffset.getX() + evt.getX(), dragOffset.getY() + evt.getY()); } else { newPos = Main.map.mapView.getLatLon(evt.getX(), evt.getY()); } photo.setPos(newPos); photo.flagNewGpsData(); layer.updateBufferAndRepaint(); // Need to re-display the photo because the OSD data might change (new // coordinates). ImageViewerDialog.showImage(layer, photo); } /** * Set the image direction, i.e. let it point to where the mouse is. * * @param photo The photo to move. * @param layer GeoImageLayer of the photo. * @param evt Mouse event from one of the mouse adapters. */ private void changeDirection(ImageEntry photo, GeoImageLayer layer, MouseEvent evt) { final LatLon photoLL = photo.getPos(); if (photoLL == null) { // Direction cannot be set if image doesn't have a position. return; } final LatLon mouseLL = Main.map.mapView.getLatLon(evt.getX(), evt.getY()); // The projection doesn't matter here. double direction = 360.0 - photoLL.heading(mouseLL) * 360.0 / 2.0 / Math.PI; if (direction < 0.0) { direction += 360.0; } else if (direction >= 360.0) { direction -= 360.0; } photo.setExifImgDir(direction); photo.flagNewGpsData(); layer.updateBufferAndRepaint(); ImageViewerDialog.showImage(layer, photo); setDragOffset(photo, evt); } }