blob: 37c2930ffe9061165beda37f316dba6bfdad9730 [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;
Ruei-sung Linf0f78442012-08-13 19:04:29 -070017import android.location.Location;
18import android.text.format.Time;
19import android.util.Log;
20
21import java.lang.Math;
22import java.util.ArrayList;
Ruei-sung Lin5d42ffa2012-08-23 16:01:57 -070023import java.util.HashMap;
24import java.util.Map;
Ruei-sung Linf0f78442012-08-13 19:04:29 -070025
26public class BaseCluster {
27
28 public static String TAG = "BaseCluster";
29
Ruei-sung Lin5d42ffa2012-08-23 16:01:57 -070030 public double[] mCenter;
31 // protected double[] mCenter;
32
33 // Histogram illustrates the pattern of visit during time of day,
34 protected HashMap<String, Long> mHistogram = new HashMap<String, Long>();
Ruei-sung Linf0f78442012-08-13 19:04:29 -070035
36 protected long mAvgInterval;
37 protected long mDuration;
38
Ruei-sung Lin5d42ffa2012-08-23 16:01:57 -070039 protected String mSemanticId;
Ruei-sung Linf0f78442012-08-13 19:04:29 -070040
Ruei-sung Lin5d42ffa2012-08-23 16:01:57 -070041 protected static final double EARTH_RADIUS = 6378100f;
Ruei-sung Linf0f78442012-08-13 19:04:29 -070042
43 public BaseCluster(Location location, long avgInterval) {
44 mAvgInterval = avgInterval;
45 mCenter = getLocationVector(location);
46
47 mDuration = 0;
48 }
49
Ruei-sung Lin5d42ffa2012-08-23 16:01:57 -070050 public BaseCluster() {
51 }
52
53 public String getSemanticId() {
54 return mSemanticId;
55 }
56
57 protected void generateSemanticId(long index) {
58 mSemanticId = "cluser: " + String.valueOf(index);
59 }
60
61 public void setSemanticId(String semanticId) {
62 mSemanticId = semanticId;
63 }
64
65 public boolean hasSemanticId() {
66 return mSemanticId != null;
67 }
68
Ruei-sung Linf0f78442012-08-13 19:04:29 -070069 protected double[] getLocationVector(Location location) {
Ruei-sung Lin5d42ffa2012-08-23 16:01:57 -070070 return getLocationVector(location.getLongitude(), location.getLatitude());
71 }
72
73 protected double[] getLocationVector(double longitude, double latitude) {
Ruei-sung Linf0f78442012-08-13 19:04:29 -070074 double vector[] = new double[3];
Ruei-sung Lin5d42ffa2012-08-23 16:01:57 -070075 double lambda = Math.toRadians(longitude);
76 double phi = Math.toRadians(latitude);
77
Ruei-sung Linf0f78442012-08-13 19:04:29 -070078 vector[0] = Math.cos(lambda) * Math.cos(phi);
79 vector[1] = Math.sin(lambda) * Math.cos(phi);
80 vector[2] = Math.sin(phi);
81 return vector;
82 }
83
Ruei-sung Lin5d42ffa2012-08-23 16:01:57 -070084 protected double getCenterLongitude() {
85 // Because latitude ranges from -90 to 90 degrees, cosPhi >= 0.
86 double cosPhi = Math.cos(Math.asin(mCenter[2]));
87 double longitude = Math.toDegrees(Math.asin(mCenter[1] / cosPhi));
88 if (mCenter[0] < 0) {
89 longitude = (longitude > 0) ? 180f - longitude : -180 - longitude;
90 }
91 return longitude;
92 }
93
94 protected double getCenterLatitude() {
95 return Math.toDegrees(Math.asin(mCenter[2]));
96 }
97
Ruei-sung Linf0f78442012-08-13 19:04:29 -070098 private double computeDistance(double[] vector1, double[] vector2) {
99 double product = 0f;
100 for (int i = 0; i < 3; ++i) {
101 product += vector1[i] * vector2[i];
102 }
103 double radian = Math.acos(Math.min(product, 1f));
104 return radian * EARTH_RADIUS;
105 }
106
107 /*
108 * This computes the distance from loation to the cluster center in meter.
109 */
110 public float distanceToCenter(Location location) {
111 return (float) computeDistance(mCenter, getLocationVector(location));
112 }
113
114 public float distanceToCluster(BaseCluster cluster) {
115 return (float) computeDistance(mCenter, cluster.mCenter);
116 }
117
118 public void absorbCluster(BaseCluster cluster) {
119 if (cluster.mAvgInterval != mAvgInterval) {
120 throw new RuntimeException(
121 "aborbing cluster failed: inconsistent average invergal ");
122 }
123
Ruei-sung Lin5d42ffa2012-08-23 16:01:57 -0700124 // the new cluster center is the average of the two clusters.
Ruei-sung Linf0f78442012-08-13 19:04:29 -0700125 double currWeight = ((double) mDuration) / (mDuration + cluster.mDuration);
126 double newWeight = 1f - currWeight;
127 double norm = 0;
128 for (int i = 0; i < 3; ++i) {
129 mCenter[i] = currWeight * mCenter[i] + newWeight * cluster.mCenter[i];
130 norm += mCenter[i] * mCenter[i];
131 }
Ruei-sung Lin5d42ffa2012-08-23 16:01:57 -0700132 // normalize the center to be unit vector
Ruei-sung Linf0f78442012-08-13 19:04:29 -0700133 for (int i = 0; i < 3; ++i) {
134 mCenter[i] /= norm;
135 }
Ruei-sung Lin5d42ffa2012-08-23 16:01:57 -0700136 absorbHistogram(cluster);
137 }
138
139 public void setCluster(BaseCluster cluster) {
140 for (int i = 0; i < 3; ++i) {
141 mCenter[i] = cluster.mCenter[i];
142 }
143 mHistogram.clear();
144 mHistogram.putAll(cluster.mHistogram);
145 mDuration = cluster.mDuration;
146 }
147
148 private void absorbHistogram(BaseCluster cluster) {
149 for (Map.Entry<String, Long> entry : cluster.mHistogram.entrySet()) {
150 String timeLabel = entry.getKey();
151 long duration = entry.getValue();
152
153 if (mHistogram.containsKey(timeLabel)) {
154 duration += mHistogram.get(timeLabel);
155 }
156 mHistogram.put(timeLabel, duration);
157 }
Ruei-sung Linf0f78442012-08-13 19:04:29 -0700158 mDuration += cluster.mDuration;
159 }
160
161 public boolean passThreshold(long durationThreshold) {
162 // TODO: might want to keep semantic cluster
163 return mDuration > durationThreshold;
164 }
Ruei-sung Lin83954e82012-08-28 18:00:48 -0700165
166 public final HashMap<String, Long> getHistogram() {
167 return mHistogram;
168 }
169
170 public void setHistogram(Map<String, Long> histogram) {
171 mHistogram.clear();
172 mHistogram.putAll(histogram);
173
174 mDuration = 0;
175 if (mHistogram.containsKey(TimeStatsAggregator.WEEKEND)) {
176 mDuration += mHistogram.get(TimeStatsAggregator.WEEKEND);
177 }
178 if (mHistogram.containsKey(TimeStatsAggregator.WEEKDAY)) {
179 mDuration += mHistogram.get(TimeStatsAggregator.WEEKDAY);
180 }
181 }
Ruei-sung Linf0f78442012-08-13 19:04:29 -0700182}