Index: trunk/src/org/openstreetmap/josm/gui/layer/geoimage/GeoImageLayer.java
===================================================================
--- trunk/src/org/openstreetmap/josm/gui/layer/geoimage/GeoImageLayer.java	(revision 18261)
+++ trunk/src/org/openstreetmap/josm/gui/layer/geoimage/GeoImageLayer.java	(revision 18263)
@@ -63,4 +63,5 @@
 import org.openstreetmap.josm.gui.layer.Layer;
 import org.openstreetmap.josm.gui.layer.MainLayerManager.ActiveLayerChangeListener;
+import org.openstreetmap.josm.gui.util.imagery.Vector3D;
 import org.openstreetmap.josm.tools.ImageProvider;
 import org.openstreetmap.josm.tools.Utils;
@@ -452,61 +453,61 @@
             if (e != null && e.getPos() != null) {
                 Point p = mv.getPoint(e.getPos());
-
-                int imgWidth;
-                int imgHeight;
-                if (useThumbs && e.hasThumbnail()) {
-                    Dimension d = scaledDimension(e.getThumbnail());
-                    if (d != null) {
-                        imgWidth = d.width;
-                        imgHeight = d.height;
-                    } else {
-                        imgWidth = -1;
-                        imgHeight = -1;
-                    }
-                } else {
-                    imgWidth = selectedIcon.getIconWidth();
-                    imgHeight = selectedIcon.getIconHeight();
-                }
+                Dimension imgDim = getImageDimension(e);
 
                 if (e.getExifImgDir() != null) {
-                    // Multiplier must be larger than sqrt(2)/2=0.71.
-                    double arrowlength = Math.max(25, Math.max(imgWidth, imgHeight) * 0.85);
-                    double arrowwidth = arrowlength / 1.4;
-
-                    double dir = e.getExifImgDir();
-                    // Rotate 90 degrees CCW
-                    double headdir = (dir < 90) ? dir + 270 : dir - 90;
-                    double leftdir = (headdir < 90) ? headdir + 270 : headdir - 90;
-                    double rightdir = (headdir > 270) ? headdir - 270 : headdir + 90;
-
-                    double ptx = p.x + Math.cos(Utils.toRadians(headdir)) * arrowlength;
-                    double pty = p.y + Math.sin(Utils.toRadians(headdir)) * arrowlength;
-
-                    double ltx = p.x + Math.cos(Utils.toRadians(leftdir)) * arrowwidth/2;
-                    double lty = p.y + Math.sin(Utils.toRadians(leftdir)) * arrowwidth/2;
-
-                    double rtx = p.x + Math.cos(Utils.toRadians(rightdir)) * arrowwidth/2;
-                    double rty = p.y + Math.sin(Utils.toRadians(rightdir)) * arrowwidth/2;
-
-                    g.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
-                    g.setColor(new Color(255, 255, 255, 192));
-                    int[] xar = {(int) ltx, (int) ptx, (int) rtx, (int) ltx};
-                    int[] yar = {(int) lty, (int) pty, (int) rty, (int) lty};
-                    g.fillPolygon(xar, yar, 4);
-                    g.setColor(Color.black);
-                    g.setStroke(new BasicStroke(1.2f));
-                    g.drawPolyline(xar, yar, 3);
+                    Vector3D imgRotation = ImageViewerDialog.getInstance().getRotation(e);
+                    drawDirectionArrow(g, p, e.getExifImgDir()
+                            + (imgRotation != null ? Utils.toDegrees(imgRotation.getPolarAngle()) : 0d), imgDim);
                 }
 
                 if (useThumbs && e.hasThumbnail()) {
                     g.setColor(new Color(128, 0, 0, 122));
-                    g.fillRect(p.x - imgWidth / 2, p.y - imgHeight / 2, imgWidth, imgHeight);
+                    g.fillRect(p.x - imgDim.width / 2, p.y - imgDim.height / 2, imgDim.width, imgDim.height);
                 } else {
                     selectedIcon.paintIcon(mv, g,
-                            p.x - imgWidth / 2,
-                            p.y - imgHeight / 2);
-                }
-            }
-        }
+                            p.x - imgDim.width / 2,
+                            p.y - imgDim.height / 2);
+                }
+            }
+        }
+    }
+
+    protected Dimension getImageDimension(ImageEntry e) {
+        if (useThumbs && e.hasThumbnail()) {
+            Dimension d = scaledDimension(e.getThumbnail());
+            return d != null ? d : new Dimension(-1, -1);
+        } else {
+            return new Dimension(selectedIcon.getIconWidth(), selectedIcon.getIconHeight());
+        }
+    }
+
+    protected static void drawDirectionArrow(Graphics2D g, Point p, double dir, Dimension imgDim) {
+        System.out.println(dir);
+        // Multiplier must be larger than sqrt(2)/2=0.71.
+        double arrowlength = Math.max(25, Math.max(imgDim.width, imgDim.height) * 0.85);
+        double arrowwidth = arrowlength / 1.4;
+
+        // Rotate 90 degrees CCW
+        double headdir = (dir < 90) ? dir + 270 : dir - 90;
+        double leftdir = (headdir < 90) ? headdir + 270 : headdir - 90;
+        double rightdir = (headdir > 270) ? headdir - 270 : headdir + 90;
+
+        double ptx = p.x + Math.cos(Utils.toRadians(headdir)) * arrowlength;
+        double pty = p.y + Math.sin(Utils.toRadians(headdir)) * arrowlength;
+
+        double ltx = p.x + Math.cos(Utils.toRadians(leftdir)) * arrowwidth/2;
+        double lty = p.y + Math.sin(Utils.toRadians(leftdir)) * arrowwidth/2;
+
+        double rtx = p.x + Math.cos(Utils.toRadians(rightdir)) * arrowwidth/2;
+        double rty = p.y + Math.sin(Utils.toRadians(rightdir)) * arrowwidth/2;
+
+        g.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
+        g.setColor(new Color(255, 255, 255, 192));
+        int[] xar = {(int) ltx, (int) ptx, (int) rtx, (int) ltx};
+        int[] yar = {(int) lty, (int) pty, (int) rty, (int) lty};
+        g.fillPolygon(xar, yar, 4);
+        g.setColor(Color.black);
+        g.setStroke(new BasicStroke(1.2f));
+        g.drawPolyline(xar, yar, 3);
     }
 
Index: trunk/src/org/openstreetmap/josm/gui/layer/geoimage/ImageDisplay.java
===================================================================
--- trunk/src/org/openstreetmap/josm/gui/layer/geoimage/ImageDisplay.java	(revision 18261)
+++ trunk/src/org/openstreetmap/josm/gui/layer/geoimage/ImageDisplay.java	(revision 18263)
@@ -32,4 +32,5 @@
 import org.openstreetmap.josm.data.preferences.IntegerProperty;
 import org.openstreetmap.josm.gui.MainApplication;
+import org.openstreetmap.josm.gui.layer.AbstractMapViewPaintable;
 import org.openstreetmap.josm.gui.layer.geoimage.viewers.projections.IImageViewer;
 import org.openstreetmap.josm.gui.layer.geoimage.viewers.projections.ImageProjectionRegistry;
@@ -37,4 +38,5 @@
 import org.openstreetmap.josm.gui.layer.imagery.ImageryFilterSettings.FilterChangeListener;
 import org.openstreetmap.josm.gui.util.GuiHelper;
+import org.openstreetmap.josm.gui.util.imagery.Vector3D;
 import org.openstreetmap.josm.spi.preferences.Config;
 import org.openstreetmap.josm.spi.preferences.PreferenceChangeEvent;
@@ -510,11 +512,15 @@
                     }
                 }
-                // We have to update the mousePointInImg for 360 image panning, as otherwise the panning
-                // never stops.
+                // We have to update the mousePointInImg for 360 image panning, as otherwise the panning never stops.
                 // This does not work well with the perspective viewer at this time (2021-08-26).
-                if (entry != null && Projections.EQUIRECTANGULAR == entry.getProjectionType()) {
+                boolean is360panning = entry != null && Projections.EQUIRECTANGULAR == entry.getProjectionType();
+                if (is360panning) {
                     this.mousePointInImg = p;
                 }
                 ImageDisplay.this.repaint();
+                if (is360panning) {
+                    // repaint direction arrow
+                    MainApplication.getLayerManager().getLayersOfType(GeoImageLayer.class).forEach(AbstractMapViewPaintable::invalidate);
+                }
             }
 
@@ -983,4 +989,14 @@
 
     /**
+     * Get the rotation in the image viewer for an entry
+     * @param entry The entry to get the rotation for. May be {@code null}.
+     * @return the current rotation in the image viewer, or {@code null}
+     * @since 18263
+     */
+    public Vector3D getRotation(IImageEntry<?> entry) {
+        return entry != null ? getIImageViewer(entry).getRotation() : null;
+    }
+
+    /**
      * Ensure that a rectangle isn't zoomed in too much
      * @param rectangle The rectangle to get (typically the visible area)
Index: trunk/src/org/openstreetmap/josm/gui/layer/geoimage/ImageViewerDialog.java
===================================================================
--- trunk/src/org/openstreetmap/josm/gui/layer/geoimage/ImageViewerDialog.java	(revision 18261)
+++ trunk/src/org/openstreetmap/josm/gui/layer/geoimage/ImageViewerDialog.java	(revision 18263)
@@ -22,4 +22,5 @@
 import java.util.concurrent.Future;
 import java.util.stream.Collectors;
+
 import javax.swing.AbstractAction;
 import javax.swing.Box;
@@ -49,4 +50,5 @@
 import org.openstreetmap.josm.gui.layer.MainLayerManager.ActiveLayerChangeListener;
 import org.openstreetmap.josm.gui.layer.imagery.ImageryFilterSettings;
+import org.openstreetmap.josm.gui.util.imagery.Vector3D;
 import org.openstreetmap.josm.tools.ImageProvider;
 import org.openstreetmap.josm.tools.Logging;
@@ -123,5 +125,5 @@
         JButton btn = new JButton(action);
         btn.setPreferredSize(buttonDim);
-        btn.addPropertyChangeListener("enabled", propertyChangeEvent -> action.setEnabled(Boolean.TRUE.equals(propertyChangeEvent.getNewValue())));
+        btn.addPropertyChangeListener("enabled", e -> action.setEnabled(Boolean.TRUE.equals(e.getNewValue())));
         return btn;
     }
@@ -626,4 +628,14 @@
 
     /**
+     * Returns the rotation of the currently displayed image.
+     * @param entry The entry to get the rotation for. May be {@code null}.
+     * @return the rotation of the currently displayed image, or {@code null}
+     * @since 18263
+     */
+    public Vector3D getRotation(IImageEntry<?> entry) {
+        return imgDisplay.getRotation(entry);
+    }
+
+    /**
      * Returns whether the center view is currently active.
      * @return {@code true} if the center view is active, {@code false} otherwise
Index: trunk/src/org/openstreetmap/josm/gui/layer/geoimage/viewers/projections/Equirectangular.java
===================================================================
--- trunk/src/org/openstreetmap/josm/gui/layer/geoimage/viewers/projections/Equirectangular.java	(revision 18261)
+++ trunk/src/org/openstreetmap/josm/gui/layer/geoimage/viewers/projections/Equirectangular.java	(revision 18263)
@@ -56,6 +56,6 @@
 
     @Override
-    public double getRotation() {
-        return this.cameraPlane.getRotation().getAzimuthalAngle();
+    public Vector3D getRotation() {
+        return this.cameraPlane.getRotation();
     }
 
Index: trunk/src/org/openstreetmap/josm/gui/layer/geoimage/viewers/projections/IImageViewer.java
===================================================================
--- trunk/src/org/openstreetmap/josm/gui/layer/geoimage/viewers/projections/IImageViewer.java	(revision 18261)
+++ trunk/src/org/openstreetmap/josm/gui/layer/geoimage/viewers/projections/IImageViewer.java	(revision 18263)
@@ -13,4 +13,5 @@
 import org.openstreetmap.josm.data.imagery.street_level.Projections;
 import org.openstreetmap.josm.gui.layer.geoimage.ImageDisplay;
+import org.openstreetmap.josm.gui.util.imagery.Vector3D;
 
 /**
@@ -45,7 +46,8 @@
      * Get the current rotation in the image viewer
      * @return The rotation
+     * @since 18263
      */
-    default double getRotation() {
-        return 0;
+    default Vector3D getRotation() {
+        return null;
     }
 
