blob: 9745d1314ddadfe3d5546af42fb329e452ca6758 [file] [log] [blame]
Ruei-sung Linf0f78442012-08-13 19:04:29 -07001/*
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 */
16package android.bordeaux.services;
17
18import android.location.Location;
19import android.text.format.Time;
20import android.util.Log;
21
22import java.lang.Math;
23import java.util.ArrayList;
24
25public class LocationCluster extends BaseCluster {
26 public static String TAG = "LocationCluster";
27
28 private static double FORGETTING_FACTOR = 0.1;
29
30 private boolean mIsNewCluster;
31
32 private ArrayList<Location> mLocations = new ArrayList<Location>();
33
34 public LocationCluster(Location location, long avgInterval) {
35 super(location, avgInterval);
36 mIsNewCluster = true;
37 }
38
39 public void addSample(Location location) {
40 mLocations.add(location);
41 }
42
43 public void consolidate(long interval) {
44 // TODO: add check on interval
45 double[] newCenter = {0f, 0f, 0f};
46 long newDuration = 0l;
47
48 // update cluster center
49 for (Location location : mLocations) {
50 double[] vector = getLocationVector(location);
51 long duration = location.getTime();
52
53 newDuration += duration;
54 for (int i = 0; i < 3; ++i) {
55 newCenter[i] += vector[i] * duration;
56 }
57 }
58 for (int i = 0; i < 3; ++i) {
59 newCenter[i] /= newDuration;
60 }
61 // remove location data
62 mLocations.clear();
63
64 if (mIsNewCluster) {
65 for (int i = 0; i < 3; ++i) {
66 mCenter[i] = newCenter[i];
67 }
68 mDuration = newDuration;
69 mIsNewCluster = false;
70 } else {
71 // the new center is weight average over latest and existing centers.
72 // fine tune the weight of new center
73 double newWeight = ((double) newDuration) / (newDuration + mDuration);
74 newWeight *= FORGETTING_FACTOR;
75 double currWeight = 1f - newWeight;
76 double norm = 0;
77 for (int i = 0; i < 3; ++i) {
78 mCenter[i] = currWeight * mCenter[i] + newWeight * newCenter[i];
79 norm += mCenter[i] * mCenter[i];
80 }
81 // normalize
82 for (int i = 0; i < 3; ++i) {
83 mCenter[i] /= norm;
84 }
85
86 newWeight = FORGETTING_FACTOR;
87 currWeight = 1f - newWeight;
88 mDuration = (long) (mDuration * currWeight + newDuration * newWeight);
89 }
90 }
91
92 /*
93 * if the new created cluster whose covered area overlaps with any existing
94 * cluster move the center away from that cluster till there is no overlap.
95 */
96 public void moveAwayCluster(LocationCluster cluster, float distance) {
97 double[] vector = new double[3];
98
99 double dot = 0f;
100 for (int i = 0; i < 3; ++i) {
101 dot += mCenter[i] * cluster.mCenter[i];
102 }
103 double norm = 0f;
104 for (int i = 0; i < 3; ++i) {
105 vector[i] = mCenter[i] - dot * cluster.mCenter[i];
106 norm += vector[i] * vector[i];
107 }
108 norm = Math.sqrt(norm);
109
110 double radian = distance / EARTH_RADIUS;
111 for (int i = 0; i < 3; ++i) {
112 mCenter[i] = cluster.mCenter[i] * Math.cos(radian) +
113 (vector[i] / norm) * Math.sin(radian);
114 }
115 }
116}