// Copyright 2008 Google Inc. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. package com.google.android.stardroid.test.control; import com.google.android.stardroid.control.AstronomerModel; import com.google.android.stardroid.control.AstronomerModelImpl; import com.google.android.stardroid.control.Clock; import com.google.android.stardroid.control.ZeroMagneticDeclinationCalculator; import com.google.android.stardroid.units.LatLong; import com.google.android.stardroid.units.Vector3; import com.google.android.stardroid.util.Geometry; import com.google.android.stardroid.util.MathUtil; import java.util.GregorianCalendar; import java.util.TimeZone; import junit.framework.TestCase; /** * Test of the {@link AstronomerModelImpl} class. * * @author John Taylor */ public class AstronomerModelTest extends TestCase { private static final float SQRT2 = MathUtil.sqrt(2f); private static final float TOL_ANGLE = 1e-3f; private static final float TOL_LENGTH = 1e-3f; private AstronomerModel astronomer; private static void assertVectorEquals(Vector3 v1, Vector3 v2, float tol_angle, float tol_length) { float normv1 = v1.length(); float normv2 = v2.length(); assertEquals("Vectors of different lengths", normv1, normv2, tol_length); float cosineSim = Geometry.cosineSimilarity(v1, v2); float cosTol = MathUtil.cos(tol_angle); assertTrue("Vectors in different directions", cosineSim >= cosTol); } @Override protected void setUp() throws Exception { super.setUp(); // For now only test a model with no magnetic correction. astronomer = new AstronomerModelImpl(new ZeroMagneticDeclinationCalculator()); } /** * Checks that our assertion method works as intended. */ public void testAssertVectorEquals_sameVector() { Vector3 v1 = new Vector3(0, 0, 1); Vector3 v2 = new Vector3(0, 0, 1); assertVectorEquals(v1, v2, 0.0001f, 0.0001f); } /** * Checks that our assertion method works as intended. */ public void testAssertVectorEquals_differentLengths() { Vector3 v1 = new Vector3(0, 0, 1.0f); Vector3 v2 = new Vector3(0, 0, 1.1f); try { assertVectorEquals(v1, v2, 0.0001f, 0.0001f); fail("Vectors should have been found to have different lengths."); } catch (junit.framework.AssertionFailedError e) { // Expected. } } /** * Checks that our assertion method works as intended. */ public void testAssertVectorEquals_differentDirections() { Vector3 v1 = new Vector3(0, 0, 1); Vector3 v2 = new Vector3(0, 1, 0); try { assertVectorEquals(v1, v2, 0.0001f, 0.0001f); fail("Vectors should have been found to point in different directions."); } catch (junit.framework.AssertionFailedError e) { // Expected. } } /** * The phone is flat, long side pointing North at lat,long = 0, 90. */ public void testSetPhoneSensorValues_phoneFlatAtLat0Long90() { LatLong location = new LatLong(0, 90); // Phone flat on back, top edge towards North // The following are in the phone's coordinate system. Vector3 acceleration = new Vector3(0, 0, -10); Vector3 magneticField = new Vector3(0, -1, 10); // The following are in the celestial coordinate system. Vector3 expectedZenith = new Vector3(0, 1, 0); Vector3 expectedNadir = new Vector3(0, -1, 0); Vector3 expectedNorth = new Vector3(0, 0, 1); Vector3 expectedEast = new Vector3(-1, 0, 0); Vector3 expectedSouth = new Vector3(0, 0, -1); Vector3 expectedWest = new Vector3(1, 0, 0); Vector3 expectedPointing = expectedNadir; Vector3 expectedUpAlongPhone = expectedNorth; checkModelOrientation(location, acceleration, magneticField, expectedZenith, expectedNadir, expectedNorth, expectedEast, expectedSouth, expectedWest, expectedPointing, expectedUpAlongPhone); } /** * As previous test, but at lat, long = (45, 0) */ public void testSetPhoneSensorValues_phoneFlatAtLat45Long0() { LatLong location = new LatLong(45, 0); Vector3 acceleration = new Vector3(0, 0, -10); Vector3 magneticField = new Vector3(0, -10, 0); Vector3 expectedZenith = new Vector3(1 / SQRT2, 0, 1 / SQRT2); Vector3 expectedNadir = new Vector3(-1 / SQRT2, 0, -1 / SQRT2); Vector3 expectedNorth = new Vector3(-1 / SQRT2, 0, 1 / SQRT2); Vector3 expectedEast = new Vector3(0, 1, 0); Vector3 expectedSouth = new Vector3(1 / SQRT2, 0, -1 / SQRT2); Vector3 expectedWest = new Vector3(0, -1, 0); Vector3 expectedPointing = expectedNadir; Vector3 expectedUpAlongPhone = expectedNorth; checkModelOrientation(location, acceleration, magneticField, expectedZenith, expectedNadir, expectedNorth, expectedEast, expectedSouth, expectedWest, expectedPointing, expectedUpAlongPhone); } /** * As previous test, but at lat, long = (0, 0) */ public void testSetPhoneSensorValues_phoneFlatOnEquatorAtMeridian() { LatLong location = new LatLong(0, 0); // Phone flat on back, top edge towards North Vector3 acceleration = new Vector3(0, 0, -10); Vector3 magneticField = new Vector3(0, -1, 10); Vector3 expectedZenith = new Vector3(1, 0, 0); Vector3 expectedNadir = new Vector3(-1, 0, 0); Vector3 expectedNorth = new Vector3(0, 0, 1); Vector3 expectedEast = new Vector3(0, 1, 0); Vector3 expectedSouth = new Vector3(0, 0, -1); Vector3 expectedWest = new Vector3(0, -1, 0); Vector3 expectedPointing = expectedNadir; Vector3 expectedUpAlongPhone = expectedNorth; checkModelOrientation(location, acceleration, magneticField, expectedZenith, expectedNadir, expectedNorth, expectedEast, expectedSouth, expectedWest, expectedPointing, expectedUpAlongPhone); } /** * As previous test, but with the phone vertical, but in landscape mode * and pointing east. */ public void testSetPhoneSensorValues_phoneLandscapeFacingEastOnEquatorAtMeridian() { LatLong location = new LatLong(0, 0); Vector3 acceleration = new Vector3(10, 0, 0); Vector3 magneticField = new Vector3(-10, 1, 0); Vector3 expectedZenith = new Vector3(1, 0, 0); Vector3 expectedNadir = new Vector3(-1, 0, 0); Vector3 expectedNorth = new Vector3(0, 0, 1); Vector3 expectedEast = new Vector3(0, 1, 0); Vector3 expectedSouth = new Vector3(0, 0, -1); Vector3 expectedWest = new Vector3(0, -1, 0); Vector3 expectedPointing = expectedEast; Vector3 expectedUpAlongPhone = expectedSouth; checkModelOrientation(location, acceleration, magneticField, expectedZenith, expectedNadir, expectedNorth, expectedEast, expectedSouth, expectedWest, expectedPointing, expectedUpAlongPhone); } /** * As previous test, but in portrait mode facing north. */ public void testSetPhoneSensorValues_phoneStandingUpFacingNorthOnEquatorAtMeridian() { LatLong location = new LatLong(0, 0); Vector3 acceleration = new Vector3(0, -10, 0); Vector3 magneticField = new Vector3(0, 10, 1); Vector3 expectedZenith = new Vector3(1, 0, 0); Vector3 expectedNadir = new Vector3(-1, 0, 0); Vector3 expectedNorth = new Vector3(0, 0, 1); Vector3 expectedEast = new Vector3(0, 1, 0); Vector3 expectedSouth = new Vector3(0, 0, -1); Vector3 expectedWest = new Vector3(0, -1, 0); Vector3 expectedPointing = expectedNorth; Vector3 expectedUpAlongPhone = expectedZenith; checkModelOrientation(location, acceleration, magneticField, expectedZenith, expectedNadir, expectedNorth, expectedEast, expectedSouth, expectedWest, expectedPointing, expectedUpAlongPhone); } private void checkModelOrientation( LatLong location, Vector3 acceleration, Vector3 magneticField, Vector3 expectedZenith, Vector3 expectedNadir, Vector3 expectedNorth, Vector3 expectedEast, Vector3 expectedSouth, Vector3 expectedWest, Vector3 expectedPointing, Vector3 expectedUpAlongPhone) { astronomer.setLocation(location); Clock fakeClock = new Clock() { @Override public long getTimeInMillisSinceEpoch() { // This date is special as RA, DEC = (0, 0) is directly overhead at the // equator on the Greenwich meridian. // 12:07 March 20th 2009 GregorianCalendar calendar = new GregorianCalendar(TimeZone.getTimeZone("UTC")); calendar.set(2009, 2, 20, 12, 07, 24); return calendar.getTimeInMillis(); } }; astronomer.setClock(fakeClock); astronomer.setPhoneSensorValues(acceleration, magneticField); assertVectorEquals(expectedZenith, astronomer.getZenith(), TOL_LENGTH, TOL_ANGLE); assertVectorEquals(expectedNadir, astronomer.getNadir(), TOL_LENGTH, TOL_ANGLE); assertVectorEquals(expectedNorth, astronomer.getNorth(), TOL_LENGTH, TOL_ANGLE); assertVectorEquals(expectedEast, astronomer.getEast(), TOL_LENGTH, TOL_ANGLE); assertVectorEquals(expectedSouth, astronomer.getSouth(), TOL_LENGTH, TOL_ANGLE); assertVectorEquals(expectedWest, astronomer.getWest(), TOL_LENGTH, TOL_ANGLE); assertVectorEquals(expectedPointing, astronomer.getPointing().getLineOfSight(), TOL_LENGTH, TOL_ANGLE); assertVectorEquals(expectedUpAlongPhone, astronomer.getPointing().getPerpendicular(), TOL_LENGTH, TOL_ANGLE); } }