Index: trunk/test/unit/org/openstreetmap/josm/gui/util/imagery/CameraPlaneTest.java
===================================================================
--- trunk/test/unit/org/openstreetmap/josm/gui/util/imagery/CameraPlaneTest.java	(revision 18246)
+++ trunk/test/unit/org/openstreetmap/josm/gui/util/imagery/CameraPlaneTest.java	(revision 18246)
@@ -0,0 +1,85 @@
+// License: GPL. For details, see LICENSE file.
+package org.openstreetmap.josm.gui.util.imagery;
+
+import static org.junit.jupiter.api.Assertions.assertAll;
+import static org.junit.jupiter.api.Assertions.assertEquals;
+
+import java.awt.Point;
+import java.awt.geom.Point2D;
+import java.util.stream.Stream;
+
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Disabled;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.params.ParameterizedTest;
+import org.junit.jupiter.params.provider.Arguments;
+import org.junit.jupiter.params.provider.MethodSource;
+
+/**
+ * Test class for {@link CameraPlane}
+ */
+class CameraPlaneTest {
+
+    private static final int CAMERA_PLANE_WIDTH = 800;
+    private static final int CAMERA_PLANE_HEIGHT = 600;
+
+    private CameraPlane cameraPlane;
+
+    @BeforeEach
+    void setUp() {
+        this.cameraPlane = new CameraPlane(CAMERA_PLANE_WIDTH, CAMERA_PLANE_HEIGHT);
+    }
+
+    @Test
+    @Disabled("Currently broken")
+    void testSetRotation() {
+        Vector3D vec = new Vector3D(0, 0, 1);
+        cameraPlane.setRotation(vec);
+        Vector3D out = cameraPlane.getRotation();
+        assertAll(() -> assertEquals(280.0830152838839, out.getRadialDistance(), 0.001),
+            () -> assertEquals(0, out.getPolarAngle(), 0.001), () -> assertEquals(0, out.getAzimuthalAngle(), 0.001));
+    }
+
+    @Test
+    @Disabled("Currently broken")
+    void testGetVector3D() {
+        Vector3D vec = new Vector3D(0, 0, 1);
+        cameraPlane.setRotation(vec);
+        Vector3D out = cameraPlane.getVector3D(new Point(CAMERA_PLANE_WIDTH / 2, CAMERA_PLANE_HEIGHT / 2));
+        assertAll(() -> assertEquals(0.0, out.getX(), 1.0E-04), () -> assertEquals(0.0, out.getY(), 1.0E-04),
+            () -> assertEquals(1.0, out.getZ(), 1.0E-04));
+    }
+
+    static Stream<Arguments> testGetVector3DFloat() {
+        return Stream
+            .of(Arguments.of(new Vector3D(0, 0, 1), new Point(CAMERA_PLANE_WIDTH / 2, CAMERA_PLANE_HEIGHT / 2)));
+    }
+
+    /**
+     * This tests a method which does not cache, and more importantly, is what is used to create the sphere.
+     * The vector is normalized.
+     * (0, 0) is the center of the image
+     *
+     * @param expected The expected vector
+     * @param toCheck The point to check
+     */
+    @ParameterizedTest
+    @MethodSource
+    void testGetVector3DFloat(final Vector3D expected, final Point toCheck) {
+        Vector3D out = cameraPlane.getVector3D(toCheck.getX(), toCheck.getY());
+        assertAll(() -> assertEquals(expected.getX(), out.getX(), 1.0E-04),
+            () -> assertEquals(expected.getY(), out.getY(), 1.0E-04),
+            () -> assertEquals(expected.getZ(), out.getZ(), 1.0E-04), () -> assertEquals(1,
+                Math.sqrt(Math.pow(out.getX(), 2) + Math.pow(out.getY(), 2) + Math.pow(out.getZ(), 2)), 1.0E-04));
+    }
+
+    @Test
+    @Disabled("Currently broken")
+    void testMapping() {
+        Vector3D vec = new Vector3D(0, 0, 1);
+        cameraPlane.setRotation(vec);
+        Vector3D out = cameraPlane.getVector3D(new Point(300, 200));
+        Point2D map = UVMapping.getTextureCoordinate(out);
+        assertAll(() -> assertEquals(0.44542099, map.getX(), 1e-8), () -> assertEquals(0.39674936, map.getY(), 1e-8));
+    }
+}
Index: trunk/test/unit/org/openstreetmap/josm/gui/util/imagery/UVMappingTest.java
===================================================================
--- trunk/test/unit/org/openstreetmap/josm/gui/util/imagery/UVMappingTest.java	(revision 18246)
+++ trunk/test/unit/org/openstreetmap/josm/gui/util/imagery/UVMappingTest.java	(revision 18246)
@@ -0,0 +1,76 @@
+// License: GPL. For details, see LICENSE file.
+package org.openstreetmap.josm.gui.util.imagery;
+import static org.junit.jupiter.api.Assertions.assertAll;
+import static org.junit.jupiter.api.Assertions.assertDoesNotThrow;
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertThrows;
+
+import java.awt.geom.Point2D;
+import java.util.stream.Stream;
+
+import org.junit.jupiter.params.ParameterizedTest;
+import org.junit.jupiter.params.provider.Arguments;
+import org.junit.jupiter.params.provider.MethodSource;
+import org.junit.jupiter.params.provider.ValueSource;
+
+/**
+ * Test class for {@link UVMapping}
+ */
+class UVMappingTest {
+    private static final double DEFAULT_DELTA = 1e-5;
+
+    static Stream<Arguments> testMapping() {
+        return Stream.of(Arguments.of(0.5, 1, 0, 1, 0),
+                Arguments.of(0.5, 0, 0, -1, 0),
+                Arguments.of(0.25, 0.5, -1, 0, 0),
+                Arguments.of(0.5, 0.5, 0, 0, 1),
+                Arguments.of(0.75, 0.5, 1, 0, 0),
+                Arguments.of(1, 0.5, 0, 0, -1),
+                Arguments.of(0.125, 0.25, -0.5, -1 / Math.sqrt(2), -0.5),
+                Arguments.of(0.625, 0.75, 0.5, 1 / Math.sqrt(2), 0.5)
+                );
+    }
+
+    /**
+     * Test that UV mapping is reversible for the sphere
+     * @param px The x for the point
+     * @param py The y for the point
+     * @param x The x portion of the vector
+     * @param y The y portion of the vector
+     * @param z The z portion of the vector
+     */
+    @ParameterizedTest
+    @MethodSource
+    void testMapping(final double px, final double py, final double x, final double y, final double z) {
+        // The mapping must be reversible
+        assertAll(() -> assertPointEquals(new Point2D.Double(px, py), UVMapping.getTextureCoordinate(new Vector3D(x, y, z))),
+                () -> assertVectorEquals(new Vector3D(x, y, z), UVMapping.getVector(px, py)));
+    }
+
+    @ParameterizedTest
+    @ValueSource(floats = {0, 1, 1.1f, 0.9f})
+    void testGetVectorEdgeCases(final float location) {
+        if (location < 0 || location > 1) {
+            assertAll(() -> assertThrows(IllegalArgumentException.class, () -> UVMapping.getVector(location, 0.5)),
+                    () -> assertThrows(IllegalArgumentException.class, () -> UVMapping.getVector(0.5, location)));
+        } else {
+            assertAll(() -> assertDoesNotThrow(() -> UVMapping.getVector(location, 0.5)),
+                    () -> assertDoesNotThrow(() -> UVMapping.getVector(0.5, location)));
+        }
+    }
+
+    private static void assertVectorEquals(final Vector3D expected, final Vector3D actual) {
+        final String message = String.format("Expected (%f %f %f), but was (%f %f %f)", expected.getX(),
+                expected.getY(), expected.getZ(), actual.getX(), actual.getY(), actual.getZ());
+        assertEquals(expected.getX(), actual.getX(), DEFAULT_DELTA, message);
+        assertEquals(expected.getY(), actual.getY(), DEFAULT_DELTA, message);
+        assertEquals(expected.getZ(), actual.getZ(), DEFAULT_DELTA, message);
+    }
+
+    private static void assertPointEquals(final Point2D expected, final Point2D actual) {
+        final String message = String.format("Expected (%f, %f), but was (%f, %f)", expected.getX(), expected.getY(),
+                actual.getX(), actual.getY());
+        assertEquals(expected.getX(), actual.getX(), DEFAULT_DELTA, message);
+        assertEquals(expected.getY(), actual.getY(), DEFAULT_DELTA, message);
+    }
+}
Index: trunk/test/unit/org/openstreetmap/josm/gui/util/imagery/Vector3DTest.java
===================================================================
--- trunk/test/unit/org/openstreetmap/josm/gui/util/imagery/Vector3DTest.java	(revision 18246)
+++ trunk/test/unit/org/openstreetmap/josm/gui/util/imagery/Vector3DTest.java	(revision 18246)
@@ -0,0 +1,88 @@
+// License: GPL. For details, see LICENSE file.
+package org.openstreetmap.josm.gui.util.imagery;
+
+import static org.junit.jupiter.api.Assertions.assertAll;
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.fail;
+
+import java.util.stream.Stream;
+
+import org.junit.jupiter.api.Disabled;
+import org.junit.jupiter.params.ParameterizedTest;
+import org.junit.jupiter.params.provider.Arguments;
+import org.junit.jupiter.params.provider.MethodSource;
+
+/**
+ * Test class for {@link Vector3D}
+ * @author Taylor Smock
+ */
+class Vector3DTest {
+
+    static Stream<Arguments> vectorInformation() {
+        return Stream.of(
+            Arguments.of(0, 0, 0, 0),
+            Arguments.of(1, 1, 1, Math.sqrt(3)),
+            Arguments.of(-1, -1, -1, Math.sqrt(3)),
+            Arguments.of(-2, 2, -2, Math.sqrt(12))
+        );
+    }
+
+    @ParameterizedTest
+    @MethodSource("vectorInformation")
+    void getX(final double x, final double y, final double z) {
+        final Vector3D vector3D = new Vector3D(x, y, z);
+        assertEquals(x, vector3D.getX());
+    }
+
+    @ParameterizedTest
+    @MethodSource("vectorInformation")
+    void getY(final double x, final double y, final double z) {
+        final Vector3D vector3D = new Vector3D(x, y, z);
+        assertEquals(y, vector3D.getY());
+    }
+
+    @ParameterizedTest
+    @MethodSource("vectorInformation")
+    void getZ(final double x, final double y, final double z) {
+        final Vector3D vector3D = new Vector3D(x, y, z);
+        assertEquals(z, vector3D.getZ());
+    }
+
+    @ParameterizedTest
+    @MethodSource("vectorInformation")
+    void getRadialDistance(final double x, final double y, final double z, final double radialDistance) {
+        final Vector3D vector3D = new Vector3D(x, y, z);
+        assertEquals(radialDistance, vector3D.getRadialDistance());
+    }
+
+    @ParameterizedTest
+    @MethodSource("vectorInformation")
+    @Disabled("Angle calculations may be corrected")
+    void getPolarAngle() {
+        fail("Not yet implemented");
+    }
+
+    @ParameterizedTest
+    @MethodSource("vectorInformation")
+    @Disabled("Angle calculations may be corrected")
+    void getAzimuthalAngle() {
+        fail("Not yet implemented");
+    }
+
+    @ParameterizedTest
+    @MethodSource("vectorInformation")
+    void normalize(final double x, final double y, final double z) {
+        final Vector3D vector3D = new Vector3D(x, y, z);
+        final Vector3D normalizedVector = vector3D.normalize();
+        assertAll(() -> assertEquals(vector3D.getRadialDistance() == 0 ? 0 : 1, normalizedVector.getRadialDistance()),
+                () -> assertEquals(vector3D.getPolarAngle(), normalizedVector.getPolarAngle()),
+                () -> assertEquals(vector3D.getAzimuthalAngle(), normalizedVector.getAzimuthalAngle()));
+    }
+
+    @ParameterizedTest
+    @MethodSource("vectorInformation")
+    @Disabled("Angle calculations may be corrected")
+    void testToString() {
+        fail("Not yet implemented");
+    }
+}
