1 /* 2 * Copyright (C) 2016 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 package com.android.cts.verifier.sensors.sixdof.Utils.Path; 17 18 import com.android.cts.verifier.sensors.sixdof.BuildConfig; 19 import com.android.cts.verifier.sensors.sixdof.Utils.Manager; 20 import com.android.cts.verifier.sensors.sixdof.Utils.MathsUtils; 21 import com.android.cts.verifier.sensors.sixdof.Utils.Exceptions.WaypointAreaCoveredException; 22 import com.android.cts.verifier.sensors.sixdof.Utils.Exceptions.WaypointDistanceException; 23 import com.android.cts.verifier.sensors.sixdof.Utils.Exceptions.WaypointStartPointException; 24 import com.android.cts.verifier.sensors.sixdof.Utils.Path.PathUtilityClasses.Waypoint; 25 26 /** 27 * Class that deals with reference waypoints. 28 */ 29 public class ReferencePath extends Path { 30 private static final float FAILURE_TOLERANCE_PERCENTAGE = 0.025f; // 2.5% 31 32 // If in Debug mode, have values that are easier to pass tests with. 33 private static final float MINIMUM_DISTANCE_FROM_WAYPOINT = (BuildConfig.DEBUG ? 0f : 3f); 34 private static final float MINIMUM_AREA_OF_TRIANGLE = (BuildConfig.DEBUG ? 0f : 2f); 35 private static final float MINIMUM_PATH_DISTANCE = (BuildConfig.DEBUG ? 0f : 10f); 36 37 private float mFailureTolerance = 0.0f; 38 39 /** 40 * @param coordinates the coordinates to use for the waypoint. 41 * @throws WaypointDistanceException if the location is too close to another 42 * @throws WaypointAreaCoveredException if the area covered by the user is too little. 43 * @throws WaypointStartPointException if the location is not close enough to the start. 44 */ 45 @Override additionalChecks(float[] coordinates)46 public void additionalChecks(float[] coordinates) 47 throws WaypointStartPointException, WaypointDistanceException, 48 WaypointAreaCoveredException { 49 testValidationSelection(coordinates); 50 } 51 52 /** 53 * Checks if the marker to remove is the first marker and removes all current path details. 54 * 55 * @return true of the first marker false if any other marker 56 */ 57 @Override removeLastMarker()58 public boolean removeLastMarker() { 59 if (mPathMarkers.size() == 1) { 60 mCurrentPath.clear(); 61 mPathMarkers.clear(); 62 return true; 63 } else { 64 return super.removeLastMarker(); 65 } 66 } 67 68 /** 69 * Calculates the path that the user still has to travel. 70 * 71 * @return The distance the user still has to travel. 72 */ calculatePathRemaining()73 public float calculatePathRemaining() { 74 float distance, pathRemaining = 0; 75 76 int currentLocation = mCurrentPath.indexOf(mPathMarkers.get(mPathMarkers.size() - 1)); 77 78 while (currentLocation < mCurrentPath.size() - 1) { 79 distance = MathsUtils.distanceCalculationOnXYPlane( 80 mCurrentPath.get(currentLocation).getCoordinates(), 81 mCurrentPath.get(currentLocation + 1).getCoordinates()); 82 pathRemaining += distance; 83 currentLocation++; 84 } 85 pathRemaining = MINIMUM_PATH_DISTANCE - pathRemaining; 86 return pathRemaining; 87 } 88 89 /** 90 * Executes the validation tests for the given waypoint. 91 * 92 * @param coordinates the location of the point to perform validations on. 93 * @throws WaypointDistanceException if the location is too close to another. 94 * @throws WaypointAreaCoveredException if the area covered by the user is too little. 95 * @throws WaypointStartPointException if the location is not close enough to the start. 96 */ testValidationSelection(float[] coordinates)97 public void testValidationSelection(float[] coordinates) throws WaypointDistanceException, 98 WaypointAreaCoveredException, WaypointStartPointException { 99 if (mPathMarkers.size() < Manager.MAX_MARKER_NUMBER - 1) { 100 validateWaypointDistance(coordinates); 101 if (mPathMarkers.size() == 2) { 102 validateAreaCovered(coordinates); 103 } 104 } else if (mPathMarkers.size() == Manager.MAX_MARKER_NUMBER - 1) { 105 validateBackToStart(coordinates); 106 } 107 } 108 109 /** 110 * Checks to make sure the waypoints added are away from other waypoints. 111 * 112 * @param coordinates the location of the point to validate the distance. 113 * @throws WaypointDistanceException WaypointDistanceException if the location is too close to 114 * another. 115 */ validateWaypointDistance(float[] coordinates)116 private void validateWaypointDistance(float[] coordinates) throws WaypointDistanceException { 117 for (Waypoint waypoint : mPathMarkers) { 118 if (MathsUtils.distanceCalculationInXYZSpace(waypoint.getCoordinates(), 119 coordinates) < MINIMUM_DISTANCE_FROM_WAYPOINT) { 120 throw new WaypointDistanceException(); 121 } 122 } 123 } 124 125 /** 126 * Checks to make sure enough distance is covered before adding the third waypoint. 127 * 128 * @param point3 the location used to validate the area. 129 * @throws WaypointAreaCoveredException if the area covered by the user is too little. 130 */ validateAreaCovered(float[] point3)131 private void validateAreaCovered(float[] point3) throws WaypointAreaCoveredException { 132 float[] A = mPathMarkers.get(0).getCoordinates(); 133 float[] B = mPathMarkers.get(1).getCoordinates(); 134 135 /* The equation used to calculate the area is: 136 * area = 1/2|(Ax - Cx)*(By - Ay) - (Ax - Bx)*(Cy - Ay) */ 137 try { 138 float part1 = (A[0] - point3[0]) * (B[1] - A[1]); 139 float part2 = (A[0] - B[0]) * (point3[1] - A[1]); 140 float area = 0.5f * Math.abs((part1 - part2)); 141 if (area <= MINIMUM_AREA_OF_TRIANGLE) { 142 throw new WaypointAreaCoveredException(); 143 } 144 } catch (ArrayIndexOutOfBoundsException e) { 145 throw new AssertionError( 146 "validateAreaCovered was given an array with a length less than 3", e); 147 } 148 149 } 150 151 /** 152 * Check the last waypoint of the first phase goes back to the start. 153 * 154 * @param coordinates the location of the point to validate the distance from the start marker. 155 * @throws WaypointStartPointException if the location is not close enough to the start. 156 */ validateBackToStart(float[] coordinates)157 private void validateBackToStart(float[] coordinates) throws WaypointStartPointException { 158 float[] firstMarkerCoordinates = mPathMarkers.get(0).getCoordinates(); 159 float distance = MathsUtils.distanceCalculationInXYZSpace( 160 firstMarkerCoordinates, coordinates); 161 162 mFailureTolerance = FAILURE_TOLERANCE_PERCENTAGE * getLengthOfCurrentPath(); 163 164 float maximumDistanceFromFirstWaypoint = (BuildConfig.DEBUG ? 1000f : mFailureTolerance); 165 166 if (distance > maximumDistanceFromFirstWaypoint) { 167 throw new WaypointStartPointException(); 168 } 169 } 170 getFailureTolerance()171 public float getFailureTolerance() { 172 return mFailureTolerance; 173 } 174 } 175