| 1 | // License: GPL. For details, see LICENSE file.
|
|---|
| 2 | package org.openstreetmap.josm.gui.layer.geoimage.viewers.projections;
|
|---|
| 3 |
|
|---|
| 4 | import java.awt.Component;
|
|---|
| 5 | import java.awt.Graphics;
|
|---|
| 6 | import java.awt.Image;
|
|---|
| 7 | import java.awt.Point;
|
|---|
| 8 | import java.awt.Rectangle;
|
|---|
| 9 | import java.awt.event.ComponentAdapter;
|
|---|
| 10 | import java.awt.event.ComponentEvent;
|
|---|
| 11 | import java.awt.image.BufferedImage;
|
|---|
| 12 | import java.util.Collections;
|
|---|
| 13 | import java.util.Set;
|
|---|
| 14 |
|
|---|
| 15 | import org.openstreetmap.josm.data.imagery.street_level.Projections;
|
|---|
| 16 | import org.openstreetmap.josm.gui.layer.geoimage.ImageDisplay;
|
|---|
| 17 | import org.openstreetmap.josm.gui.util.GuiHelper;
|
|---|
| 18 | import org.openstreetmap.josm.gui.util.imagery.CameraPlane;
|
|---|
| 19 | import org.openstreetmap.josm.gui.util.imagery.Vector3D;
|
|---|
| 20 |
|
|---|
| 21 | import jakarta.annotation.Nonnull;
|
|---|
| 22 | import jakarta.annotation.Nullable;
|
|---|
| 23 |
|
|---|
| 24 | /**
|
|---|
| 25 | * A class for showing 360 images that use the equirectangular projection
|
|---|
| 26 | * @author Taylor Smock
|
|---|
| 27 | * @since 18246
|
|---|
| 28 | */
|
|---|
| 29 | public class Equirectangular extends ComponentAdapter implements IImageViewer {
|
|---|
| 30 | @Nullable
|
|---|
| 31 | private volatile CameraPlane cameraPlane;
|
|---|
| 32 | private volatile BufferedImage offscreenImage;
|
|---|
| 33 |
|
|---|
| 34 | @Override
|
|---|
| 35 | public Set<Projections> getSupportedProjections() {
|
|---|
| 36 | return Collections.singleton(Projections.EQUIRECTANGULAR);
|
|---|
| 37 | }
|
|---|
| 38 |
|
|---|
| 39 | @Override
|
|---|
| 40 | public void paintImage(Graphics g, BufferedImage image, Rectangle target, Rectangle visibleRect) {
|
|---|
| 41 | final CameraPlane currentCameraPlane;
|
|---|
| 42 | final BufferedImage currentOffscreenImage;
|
|---|
| 43 | synchronized (this) {
|
|---|
| 44 | final CameraPlane currentPlane = this.cameraPlane;
|
|---|
| 45 | currentCameraPlane = currentPlane != null ? currentPlane : this.updateCameraPlane(target.width, target.height);
|
|---|
| 46 | currentOffscreenImage = this.offscreenImage;
|
|---|
| 47 | }
|
|---|
| 48 | currentCameraPlane.mapping(image, currentOffscreenImage, visibleRect);
|
|---|
| 49 | if (target == null) {
|
|---|
| 50 | target = new Rectangle(0, 0, currentOffscreenImage.getWidth(null), currentOffscreenImage.getHeight(null));
|
|---|
| 51 | }
|
|---|
| 52 | g.drawImage(currentOffscreenImage, target.x, target.y, target.x + target.width, target.y + target.height,
|
|---|
| 53 | visibleRect.x, visibleRect.y, visibleRect.x + visibleRect.width, visibleRect.y + visibleRect.height,
|
|---|
| 54 | null);
|
|---|
| 55 | }
|
|---|
| 56 |
|
|---|
| 57 | @Override
|
|---|
| 58 | public ImageDisplay.VisRect getDefaultVisibleRectangle(Component component, Image image) {
|
|---|
| 59 | return new ImageDisplay.VisRect(0, 0, component.getSize().width, component.getSize().height);
|
|---|
| 60 | }
|
|---|
| 61 |
|
|---|
| 62 | @Override
|
|---|
| 63 | public Vector3D getRotation() {
|
|---|
| 64 | final CameraPlane currentPlane = this.cameraPlane;
|
|---|
| 65 | if (currentPlane != null) {
|
|---|
| 66 | return currentPlane.getRotation();
|
|---|
| 67 | }
|
|---|
| 68 | return IImageViewer.super.getRotation();
|
|---|
| 69 | }
|
|---|
| 70 |
|
|---|
| 71 | @Override
|
|---|
| 72 | public void componentResized(ComponentEvent e) {
|
|---|
| 73 | final Component imgDisplay = e.getComponent();
|
|---|
| 74 | if (e.getComponent().getWidth() > 0
|
|---|
| 75 | && e.getComponent().getHeight() > 0) {
|
|---|
| 76 | updateCameraPlane(imgDisplay.getWidth(), imgDisplay.getHeight());
|
|---|
| 77 | if (imgDisplay instanceof ImageDisplay) {
|
|---|
| 78 | ((ImageDisplay) imgDisplay).updateVisibleRectangle();
|
|---|
| 79 | }
|
|---|
| 80 | GuiHelper.runInEDT(imgDisplay::revalidate);
|
|---|
| 81 | }
|
|---|
| 82 | }
|
|---|
| 83 |
|
|---|
| 84 | /**
|
|---|
| 85 | * Update the current camera plane
|
|---|
| 86 | * @param width The width to use
|
|---|
| 87 | * @param height The height to use
|
|---|
| 88 | */
|
|---|
| 89 | @Nonnull
|
|---|
| 90 | private CameraPlane updateCameraPlane(int width, int height) {
|
|---|
| 91 | // FIXME: Do something so that the types of the images are the same between the offscreenImage and
|
|---|
| 92 | // the image entry
|
|---|
| 93 | final CameraPlane currentCameraPlane;
|
|---|
| 94 | synchronized (this) {
|
|---|
| 95 | currentCameraPlane = this.cameraPlane;
|
|---|
| 96 | }
|
|---|
| 97 | final BufferedImage temporaryOffscreenImage = new BufferedImage(width, height,
|
|---|
| 98 | BufferedImage.TYPE_4BYTE_ABGR);
|
|---|
| 99 |
|
|---|
| 100 | Vector3D currentRotation = null;
|
|---|
| 101 | if (currentCameraPlane != null) {
|
|---|
| 102 | currentRotation = currentCameraPlane.getRotation();
|
|---|
| 103 | }
|
|---|
| 104 | final CameraPlane temporaryCameraPlane = new CameraPlane(width, height);
|
|---|
| 105 | if (currentRotation != null) {
|
|---|
| 106 | temporaryCameraPlane.setRotation(currentRotation);
|
|---|
| 107 | }
|
|---|
| 108 | synchronized (this) {
|
|---|
| 109 | this.cameraPlane = temporaryCameraPlane;
|
|---|
| 110 | this.offscreenImage = temporaryOffscreenImage;
|
|---|
| 111 | }
|
|---|
| 112 | return temporaryCameraPlane;
|
|---|
| 113 | }
|
|---|
| 114 |
|
|---|
| 115 | @Override
|
|---|
| 116 | public void mouseDragged(final Point from, final Point to, ImageDisplay.VisRect currentVisibleRect) {
|
|---|
| 117 | final CameraPlane currentPlane = this.cameraPlane;
|
|---|
| 118 | if (from != null && to != null && currentPlane != null) {
|
|---|
| 119 | currentPlane.setRotationFromDelta(from, to);
|
|---|
| 120 | }
|
|---|
| 121 | }
|
|---|
| 122 |
|
|---|
| 123 | @Override
|
|---|
| 124 | public void checkAndModifyVisibleRectSize(Image image, ImageDisplay.VisRect visibleRect) {
|
|---|
| 125 | IImageViewer.super.checkAndModifyVisibleRectSize(this.offscreenImage, visibleRect);
|
|---|
| 126 | }
|
|---|
| 127 |
|
|---|
| 128 | @Override
|
|---|
| 129 | public Image getMaxImageSize(ImageDisplay imageDisplay, Image image) {
|
|---|
| 130 | return this.offscreenImage;
|
|---|
| 131 | }
|
|---|
| 132 | }
|
|---|