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