Home | History | Annotate | Download | only in services
      1 /*
      2  * Copyright (C) 2012 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 android.bordeaux.services;
     17 
     18 import android.location.Location;
     19 import android.text.format.Time;
     20 import android.util.Log;
     21 
     22 import java.lang.Math;
     23 import java.util.ArrayList;
     24 import java.util.HashMap;
     25 import java.util.Map;
     26 
     27 public class LocationCluster extends BaseCluster {
     28     public static String TAG = "LocationCluster";
     29 
     30     private ArrayList<Location> mLocations = new ArrayList<Location>();
     31     private HashMap<String, Long> mNewHistogram = new HashMap<String, Long>();
     32 
     33     private String mSemanticClusterId = null;
     34 
     35     public void setSemanticClusterId(String semanticClusterId) {
     36         mSemanticClusterId = semanticClusterId;
     37     }
     38 
     39     public String getSemanticClusterId() {
     40         return mSemanticClusterId;
     41     }
     42 
     43     public boolean hasSemanticClusterId() {
     44         return mSemanticClusterId != null;
     45     }
     46 
     47     // TODO: make it a singleton class
     48     public LocationCluster(Location location, long duration) {
     49         super(location);
     50         addSample(location, duration);
     51     }
     52 
     53     public void addSample(Location location, long duration) {
     54         updateTemporalHistogram(location.getTime(), duration);
     55 
     56         // use time field to store duation of this location
     57         // TODO: extend Location class with additional field for this.
     58         location.setTime(duration);
     59         mLocations.add(location);
     60     }
     61 
     62     public void consolidate() {
     63         // If there is no new location added during this period, do nothing.
     64         if (mLocations.size() == 0) {
     65             return;
     66         }
     67 
     68         double[] newCenter = {0f, 0f, 0f};
     69         long newDuration = 0l;
     70         // update cluster center
     71         for (Location location : mLocations) {
     72             double[] vector = getLocationVector(location);
     73             long duration = location.getTime(); // in seconds
     74 
     75             if (duration == 0) {
     76                 throw new RuntimeException("location duration is zero");
     77             }
     78 
     79             newDuration += duration;
     80             for (int i = 0; i < VECTOR_LENGTH; ++i) {
     81                 newCenter[i] += vector[i] * duration;
     82             }
     83         }
     84         if (newDuration == 0l) {
     85             throw new RuntimeException("new duration is zero!");
     86         }
     87         for (int i = 0; i < VECTOR_LENGTH; ++i) {
     88             newCenter[i] /= newDuration;
     89         }
     90         // remove location data
     91         mLocations.clear();
     92 
     93         // The updated center is the weighted average of the existing and the new
     94         // centers. Note that if the cluster is consolidated for the first time,
     95         // the weight for the existing cluster would be zero.
     96         averageCenter(newCenter, newDuration);
     97 
     98         // update histogram
     99         for (Map.Entry<String, Long> entry : mNewHistogram.entrySet()) {
    100             String timeLabel = entry.getKey();
    101             long duration = entry.getValue();
    102             if (mHistogram.containsKey(timeLabel)) {
    103                 duration += mHistogram.get(timeLabel);
    104             }
    105             mHistogram.put(timeLabel, duration);
    106         }
    107         mDuration += newDuration;
    108         mNewHistogram.clear();
    109     }
    110 
    111     /*
    112      * if the new created cluster whose covered area overlaps with any existing
    113      * cluster move the center away from that cluster till there is no overlap.
    114      */
    115     public void moveAwayCluster(LocationCluster cluster, float distance) {
    116         double[] vector = new double[VECTOR_LENGTH];
    117 
    118         double dot = 0f;
    119         for (int i = 0; i < VECTOR_LENGTH; ++i) {
    120             dot += mCenter[i] * cluster.mCenter[i];
    121         }
    122         double norm = 0f;
    123         for (int i = 0; i < VECTOR_LENGTH; ++i) {
    124             vector[i] = mCenter[i] - dot * cluster.mCenter[i];
    125             norm += vector[i] * vector[i];
    126         }
    127         norm = Math.sqrt(norm);
    128 
    129         double radian = distance / EARTH_RADIUS;
    130         for (int i = 0; i < VECTOR_LENGTH; ++i) {
    131             mCenter[i] = cluster.mCenter[i] * Math.cos(radian) +
    132                     (vector[i] / norm) * Math.sin(radian);
    133         }
    134     }
    135 
    136     private void updateTemporalHistogram(long time, long duration) {
    137         HashMap<String, String> timeFeatures = TimeStatsAggregator.getAllTimeFeatures(time);
    138 
    139         String timeOfWeek = timeFeatures.get(TimeStatsAggregator.TIME_OF_WEEK);
    140         long totalDuration = (mNewHistogram.containsKey(timeOfWeek)) ?
    141             mNewHistogram.get(timeOfWeek) + duration : duration;
    142         mNewHistogram.put(timeOfWeek, totalDuration);
    143 
    144         String timeOfDay = timeFeatures.get(TimeStatsAggregator.TIME_OF_DAY);
    145         totalDuration = (mNewHistogram.containsKey(timeOfDay)) ?
    146             mNewHistogram.get(timeOfDay) + duration : duration;
    147         mNewHistogram.put(timeOfDay, totalDuration);
    148     }
    149 }
    150