Home | History | Annotate | Download | only in Path
      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
     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
     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      */
     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      */
     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      */
    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      */
    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      */
    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 
    171     public float getFailureTolerance() {
    172         return mFailureTolerance;
    173     }
    174 }
    175