1f0f78449e8ab7d63894964c54b6ef390ca9ce044Ruei-sung Lin/* 2f0f78449e8ab7d63894964c54b6ef390ca9ce044Ruei-sung Lin * Copyright (C) 2012 The Android Open Source Project 3f0f78449e8ab7d63894964c54b6ef390ca9ce044Ruei-sung Lin * 4f0f78449e8ab7d63894964c54b6ef390ca9ce044Ruei-sung Lin * Licensed under the Apache License, Version 2.0 (the "License"); 5f0f78449e8ab7d63894964c54b6ef390ca9ce044Ruei-sung Lin * you may not use this file except in compliance with the License. 6f0f78449e8ab7d63894964c54b6ef390ca9ce044Ruei-sung Lin * You may obtain a copy of the License at 7f0f78449e8ab7d63894964c54b6ef390ca9ce044Ruei-sung Lin * 8f0f78449e8ab7d63894964c54b6ef390ca9ce044Ruei-sung Lin * http://www.apache.org/licenses/LICENSE-2.0 9f0f78449e8ab7d63894964c54b6ef390ca9ce044Ruei-sung Lin * 10f0f78449e8ab7d63894964c54b6ef390ca9ce044Ruei-sung Lin * Unless required by applicable law or agreed to in writing, software 11f0f78449e8ab7d63894964c54b6ef390ca9ce044Ruei-sung Lin * distributed under the License is distributed on an "AS IS" BASIS, 12f0f78449e8ab7d63894964c54b6ef390ca9ce044Ruei-sung Lin * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13f0f78449e8ab7d63894964c54b6ef390ca9ce044Ruei-sung Lin * See the License for the specific language governing permissions and 14f0f78449e8ab7d63894964c54b6ef390ca9ce044Ruei-sung Lin * limitations under the License. 15f0f78449e8ab7d63894964c54b6ef390ca9ce044Ruei-sung Lin */ 16f0f78449e8ab7d63894964c54b6ef390ca9ce044Ruei-sung Linpackage android.bordeaux.services; 17f0f78449e8ab7d63894964c54b6ef390ca9ce044Ruei-sung Linimport android.location.Location; 18f0f78449e8ab7d63894964c54b6ef390ca9ce044Ruei-sung Linimport android.text.format.Time; 19f0f78449e8ab7d63894964c54b6ef390ca9ce044Ruei-sung Linimport android.util.Log; 20f0f78449e8ab7d63894964c54b6ef390ca9ce044Ruei-sung Lin 21f0f78449e8ab7d63894964c54b6ef390ca9ce044Ruei-sung Linimport java.lang.Math; 22f0f78449e8ab7d63894964c54b6ef390ca9ce044Ruei-sung Linimport java.util.ArrayList; 235d42ffa9462f87edbbdc61a8719f6c521c700de5Ruei-sung Linimport java.util.HashMap; 245d42ffa9462f87edbbdc61a8719f6c521c700de5Ruei-sung Linimport java.util.Map; 25f0f78449e8ab7d63894964c54b6ef390ca9ce044Ruei-sung Lin 26f0f78449e8ab7d63894964c54b6ef390ca9ce044Ruei-sung Linpublic class BaseCluster { 27f0f78449e8ab7d63894964c54b6ef390ca9ce044Ruei-sung Lin 28f0f78449e8ab7d63894964c54b6ef390ca9ce044Ruei-sung Lin public static String TAG = "BaseCluster"; 29f0f78449e8ab7d63894964c54b6ef390ca9ce044Ruei-sung Lin 305d42ffa9462f87edbbdc61a8719f6c521c700de5Ruei-sung Lin public double[] mCenter; 315d42ffa9462f87edbbdc61a8719f6c521c700de5Ruei-sung Lin // protected double[] mCenter; 325d42ffa9462f87edbbdc61a8719f6c521c700de5Ruei-sung Lin 331253e9fb0b5570ab8adaed222655a5b052aa072eRuei-sung Lin protected static final int VECTOR_LENGTH = 3; 341253e9fb0b5570ab8adaed222655a5b052aa072eRuei-sung Lin 351253e9fb0b5570ab8adaed222655a5b052aa072eRuei-sung Lin private static final long FORGETTING_ENUMERATOR = 95; 361253e9fb0b5570ab8adaed222655a5b052aa072eRuei-sung Lin private static final long FORGETTING_DENOMINATOR = 100; 371253e9fb0b5570ab8adaed222655a5b052aa072eRuei-sung Lin 385d42ffa9462f87edbbdc61a8719f6c521c700de5Ruei-sung Lin // Histogram illustrates the pattern of visit during time of day, 395d42ffa9462f87edbbdc61a8719f6c521c700de5Ruei-sung Lin protected HashMap<String, Long> mHistogram = new HashMap<String, Long>(); 40f0f78449e8ab7d63894964c54b6ef390ca9ce044Ruei-sung Lin 41f0f78449e8ab7d63894964c54b6ef390ca9ce044Ruei-sung Lin protected long mDuration; 42f0f78449e8ab7d63894964c54b6ef390ca9ce044Ruei-sung Lin 435d42ffa9462f87edbbdc61a8719f6c521c700de5Ruei-sung Lin protected String mSemanticId; 44f0f78449e8ab7d63894964c54b6ef390ca9ce044Ruei-sung Lin 455d42ffa9462f87edbbdc61a8719f6c521c700de5Ruei-sung Lin protected static final double EARTH_RADIUS = 6378100f; 46f0f78449e8ab7d63894964c54b6ef390ca9ce044Ruei-sung Lin 4778a66d98346a69f65e9d38bb0c96a5418c007197Ruei-sung Lin public BaseCluster(Location location) { 48f0f78449e8ab7d63894964c54b6ef390ca9ce044Ruei-sung Lin mCenter = getLocationVector(location); 49f0f78449e8ab7d63894964c54b6ef390ca9ce044Ruei-sung Lin mDuration = 0; 50f0f78449e8ab7d63894964c54b6ef390ca9ce044Ruei-sung Lin } 51f0f78449e8ab7d63894964c54b6ef390ca9ce044Ruei-sung Lin 521253e9fb0b5570ab8adaed222655a5b052aa072eRuei-sung Lin public BaseCluster(String semanticId, double longitude, double latitude, 531253e9fb0b5570ab8adaed222655a5b052aa072eRuei-sung Lin long duration) { 541253e9fb0b5570ab8adaed222655a5b052aa072eRuei-sung Lin mSemanticId = semanticId; 551253e9fb0b5570ab8adaed222655a5b052aa072eRuei-sung Lin mCenter = getLocationVector(longitude, latitude); 561253e9fb0b5570ab8adaed222655a5b052aa072eRuei-sung Lin mDuration = duration; 575d42ffa9462f87edbbdc61a8719f6c521c700de5Ruei-sung Lin } 585d42ffa9462f87edbbdc61a8719f6c521c700de5Ruei-sung Lin 595d42ffa9462f87edbbdc61a8719f6c521c700de5Ruei-sung Lin public String getSemanticId() { 605d42ffa9462f87edbbdc61a8719f6c521c700de5Ruei-sung Lin return mSemanticId; 615d42ffa9462f87edbbdc61a8719f6c521c700de5Ruei-sung Lin } 625d42ffa9462f87edbbdc61a8719f6c521c700de5Ruei-sung Lin 631253e9fb0b5570ab8adaed222655a5b052aa072eRuei-sung Lin public void generateSemanticId(long index) { 645d42ffa9462f87edbbdc61a8719f6c521c700de5Ruei-sung Lin mSemanticId = "cluser: " + String.valueOf(index); 655d42ffa9462f87edbbdc61a8719f6c521c700de5Ruei-sung Lin } 665d42ffa9462f87edbbdc61a8719f6c521c700de5Ruei-sung Lin 671253e9fb0b5570ab8adaed222655a5b052aa072eRuei-sung Lin public long getDuration() { 681253e9fb0b5570ab8adaed222655a5b052aa072eRuei-sung Lin return mDuration; 695d42ffa9462f87edbbdc61a8719f6c521c700de5Ruei-sung Lin } 705d42ffa9462f87edbbdc61a8719f6c521c700de5Ruei-sung Lin 715d42ffa9462f87edbbdc61a8719f6c521c700de5Ruei-sung Lin public boolean hasSemanticId() { 725d42ffa9462f87edbbdc61a8719f6c521c700de5Ruei-sung Lin return mSemanticId != null; 735d42ffa9462f87edbbdc61a8719f6c521c700de5Ruei-sung Lin } 745d42ffa9462f87edbbdc61a8719f6c521c700de5Ruei-sung Lin 75f0f78449e8ab7d63894964c54b6ef390ca9ce044Ruei-sung Lin protected double[] getLocationVector(Location location) { 765d42ffa9462f87edbbdc61a8719f6c521c700de5Ruei-sung Lin return getLocationVector(location.getLongitude(), location.getLatitude()); 775d42ffa9462f87edbbdc61a8719f6c521c700de5Ruei-sung Lin } 785d42ffa9462f87edbbdc61a8719f6c521c700de5Ruei-sung Lin 795d42ffa9462f87edbbdc61a8719f6c521c700de5Ruei-sung Lin protected double[] getLocationVector(double longitude, double latitude) { 801253e9fb0b5570ab8adaed222655a5b052aa072eRuei-sung Lin double vector[] = new double[VECTOR_LENGTH]; 815d42ffa9462f87edbbdc61a8719f6c521c700de5Ruei-sung Lin double lambda = Math.toRadians(longitude); 825d42ffa9462f87edbbdc61a8719f6c521c700de5Ruei-sung Lin double phi = Math.toRadians(latitude); 835d42ffa9462f87edbbdc61a8719f6c521c700de5Ruei-sung Lin 84f0f78449e8ab7d63894964c54b6ef390ca9ce044Ruei-sung Lin vector[0] = Math.cos(lambda) * Math.cos(phi); 85f0f78449e8ab7d63894964c54b6ef390ca9ce044Ruei-sung Lin vector[1] = Math.sin(lambda) * Math.cos(phi); 86f0f78449e8ab7d63894964c54b6ef390ca9ce044Ruei-sung Lin vector[2] = Math.sin(phi); 87f0f78449e8ab7d63894964c54b6ef390ca9ce044Ruei-sung Lin return vector; 88f0f78449e8ab7d63894964c54b6ef390ca9ce044Ruei-sung Lin } 89f0f78449e8ab7d63894964c54b6ef390ca9ce044Ruei-sung Lin 905d42ffa9462f87edbbdc61a8719f6c521c700de5Ruei-sung Lin protected double getCenterLongitude() { 915d42ffa9462f87edbbdc61a8719f6c521c700de5Ruei-sung Lin // Because latitude ranges from -90 to 90 degrees, cosPhi >= 0. 925d42ffa9462f87edbbdc61a8719f6c521c700de5Ruei-sung Lin double cosPhi = Math.cos(Math.asin(mCenter[2])); 935d42ffa9462f87edbbdc61a8719f6c521c700de5Ruei-sung Lin double longitude = Math.toDegrees(Math.asin(mCenter[1] / cosPhi)); 945d42ffa9462f87edbbdc61a8719f6c521c700de5Ruei-sung Lin if (mCenter[0] < 0) { 955d42ffa9462f87edbbdc61a8719f6c521c700de5Ruei-sung Lin longitude = (longitude > 0) ? 180f - longitude : -180 - longitude; 965d42ffa9462f87edbbdc61a8719f6c521c700de5Ruei-sung Lin } 975d42ffa9462f87edbbdc61a8719f6c521c700de5Ruei-sung Lin return longitude; 985d42ffa9462f87edbbdc61a8719f6c521c700de5Ruei-sung Lin } 995d42ffa9462f87edbbdc61a8719f6c521c700de5Ruei-sung Lin 1005d42ffa9462f87edbbdc61a8719f6c521c700de5Ruei-sung Lin protected double getCenterLatitude() { 1015d42ffa9462f87edbbdc61a8719f6c521c700de5Ruei-sung Lin return Math.toDegrees(Math.asin(mCenter[2])); 1025d42ffa9462f87edbbdc61a8719f6c521c700de5Ruei-sung Lin } 1035d42ffa9462f87edbbdc61a8719f6c521c700de5Ruei-sung Lin 104f0f78449e8ab7d63894964c54b6ef390ca9ce044Ruei-sung Lin private double computeDistance(double[] vector1, double[] vector2) { 105f0f78449e8ab7d63894964c54b6ef390ca9ce044Ruei-sung Lin double product = 0f; 1061253e9fb0b5570ab8adaed222655a5b052aa072eRuei-sung Lin for (int i = 0; i < VECTOR_LENGTH; ++i) { 107f0f78449e8ab7d63894964c54b6ef390ca9ce044Ruei-sung Lin product += vector1[i] * vector2[i]; 108f0f78449e8ab7d63894964c54b6ef390ca9ce044Ruei-sung Lin } 109f0f78449e8ab7d63894964c54b6ef390ca9ce044Ruei-sung Lin double radian = Math.acos(Math.min(product, 1f)); 110f0f78449e8ab7d63894964c54b6ef390ca9ce044Ruei-sung Lin return radian * EARTH_RADIUS; 111f0f78449e8ab7d63894964c54b6ef390ca9ce044Ruei-sung Lin } 112f0f78449e8ab7d63894964c54b6ef390ca9ce044Ruei-sung Lin 113f0f78449e8ab7d63894964c54b6ef390ca9ce044Ruei-sung Lin /* 114f0f78449e8ab7d63894964c54b6ef390ca9ce044Ruei-sung Lin * This computes the distance from loation to the cluster center in meter. 115f0f78449e8ab7d63894964c54b6ef390ca9ce044Ruei-sung Lin */ 116f0f78449e8ab7d63894964c54b6ef390ca9ce044Ruei-sung Lin public float distanceToCenter(Location location) { 117f0f78449e8ab7d63894964c54b6ef390ca9ce044Ruei-sung Lin return (float) computeDistance(mCenter, getLocationVector(location)); 118f0f78449e8ab7d63894964c54b6ef390ca9ce044Ruei-sung Lin } 119f0f78449e8ab7d63894964c54b6ef390ca9ce044Ruei-sung Lin 120f0f78449e8ab7d63894964c54b6ef390ca9ce044Ruei-sung Lin public float distanceToCluster(BaseCluster cluster) { 121f0f78449e8ab7d63894964c54b6ef390ca9ce044Ruei-sung Lin return (float) computeDistance(mCenter, cluster.mCenter); 122f0f78449e8ab7d63894964c54b6ef390ca9ce044Ruei-sung Lin } 123f0f78449e8ab7d63894964c54b6ef390ca9ce044Ruei-sung Lin 124f0f78449e8ab7d63894964c54b6ef390ca9ce044Ruei-sung Lin public void absorbCluster(BaseCluster cluster) { 1251253e9fb0b5570ab8adaed222655a5b052aa072eRuei-sung Lin averageCenter(cluster.mCenter, cluster.mDuration); 1265d42ffa9462f87edbbdc61a8719f6c521c700de5Ruei-sung Lin absorbHistogram(cluster); 1275d42ffa9462f87edbbdc61a8719f6c521c700de5Ruei-sung Lin } 1285d42ffa9462f87edbbdc61a8719f6c521c700de5Ruei-sung Lin 1295d42ffa9462f87edbbdc61a8719f6c521c700de5Ruei-sung Lin public void setCluster(BaseCluster cluster) { 1301253e9fb0b5570ab8adaed222655a5b052aa072eRuei-sung Lin for (int i = 0; i < VECTOR_LENGTH; ++i) { 1315d42ffa9462f87edbbdc61a8719f6c521c700de5Ruei-sung Lin mCenter[i] = cluster.mCenter[i]; 1325d42ffa9462f87edbbdc61a8719f6c521c700de5Ruei-sung Lin } 1335d42ffa9462f87edbbdc61a8719f6c521c700de5Ruei-sung Lin mHistogram.clear(); 1345d42ffa9462f87edbbdc61a8719f6c521c700de5Ruei-sung Lin mHistogram.putAll(cluster.mHistogram); 1355d42ffa9462f87edbbdc61a8719f6c521c700de5Ruei-sung Lin mDuration = cluster.mDuration; 1365d42ffa9462f87edbbdc61a8719f6c521c700de5Ruei-sung Lin } 1375d42ffa9462f87edbbdc61a8719f6c521c700de5Ruei-sung Lin 1385d42ffa9462f87edbbdc61a8719f6c521c700de5Ruei-sung Lin private void absorbHistogram(BaseCluster cluster) { 1395d42ffa9462f87edbbdc61a8719f6c521c700de5Ruei-sung Lin for (Map.Entry<String, Long> entry : cluster.mHistogram.entrySet()) { 1405d42ffa9462f87edbbdc61a8719f6c521c700de5Ruei-sung Lin String timeLabel = entry.getKey(); 1415d42ffa9462f87edbbdc61a8719f6c521c700de5Ruei-sung Lin long duration = entry.getValue(); 1425d42ffa9462f87edbbdc61a8719f6c521c700de5Ruei-sung Lin 1435d42ffa9462f87edbbdc61a8719f6c521c700de5Ruei-sung Lin if (mHistogram.containsKey(timeLabel)) { 1445d42ffa9462f87edbbdc61a8719f6c521c700de5Ruei-sung Lin duration += mHistogram.get(timeLabel); 1455d42ffa9462f87edbbdc61a8719f6c521c700de5Ruei-sung Lin } 1465d42ffa9462f87edbbdc61a8719f6c521c700de5Ruei-sung Lin mHistogram.put(timeLabel, duration); 1475d42ffa9462f87edbbdc61a8719f6c521c700de5Ruei-sung Lin } 148f0f78449e8ab7d63894964c54b6ef390ca9ce044Ruei-sung Lin mDuration += cluster.mDuration; 149f0f78449e8ab7d63894964c54b6ef390ca9ce044Ruei-sung Lin } 150f0f78449e8ab7d63894964c54b6ef390ca9ce044Ruei-sung Lin 151f0f78449e8ab7d63894964c54b6ef390ca9ce044Ruei-sung Lin public boolean passThreshold(long durationThreshold) { 152f0f78449e8ab7d63894964c54b6ef390ca9ce044Ruei-sung Lin // TODO: might want to keep semantic cluster 153f0f78449e8ab7d63894964c54b6ef390ca9ce044Ruei-sung Lin return mDuration > durationThreshold; 154f0f78449e8ab7d63894964c54b6ef390ca9ce044Ruei-sung Lin } 15583954e853dc1e1a28b2c3efbe1585f188266df02Ruei-sung Lin 15683954e853dc1e1a28b2c3efbe1585f188266df02Ruei-sung Lin public final HashMap<String, Long> getHistogram() { 15783954e853dc1e1a28b2c3efbe1585f188266df02Ruei-sung Lin return mHistogram; 15883954e853dc1e1a28b2c3efbe1585f188266df02Ruei-sung Lin } 15983954e853dc1e1a28b2c3efbe1585f188266df02Ruei-sung Lin 16083954e853dc1e1a28b2c3efbe1585f188266df02Ruei-sung Lin public void setHistogram(Map<String, Long> histogram) { 16183954e853dc1e1a28b2c3efbe1585f188266df02Ruei-sung Lin mHistogram.clear(); 16283954e853dc1e1a28b2c3efbe1585f188266df02Ruei-sung Lin mHistogram.putAll(histogram); 16383954e853dc1e1a28b2c3efbe1585f188266df02Ruei-sung Lin 16483954e853dc1e1a28b2c3efbe1585f188266df02Ruei-sung Lin mDuration = 0; 16583954e853dc1e1a28b2c3efbe1585f188266df02Ruei-sung Lin if (mHistogram.containsKey(TimeStatsAggregator.WEEKEND)) { 16683954e853dc1e1a28b2c3efbe1585f188266df02Ruei-sung Lin mDuration += mHistogram.get(TimeStatsAggregator.WEEKEND); 16783954e853dc1e1a28b2c3efbe1585f188266df02Ruei-sung Lin } 16883954e853dc1e1a28b2c3efbe1585f188266df02Ruei-sung Lin if (mHistogram.containsKey(TimeStatsAggregator.WEEKDAY)) { 16983954e853dc1e1a28b2c3efbe1585f188266df02Ruei-sung Lin mDuration += mHistogram.get(TimeStatsAggregator.WEEKDAY); 17083954e853dc1e1a28b2c3efbe1585f188266df02Ruei-sung Lin } 17183954e853dc1e1a28b2c3efbe1585f188266df02Ruei-sung Lin } 1721253e9fb0b5570ab8adaed222655a5b052aa072eRuei-sung Lin 1731253e9fb0b5570ab8adaed222655a5b052aa072eRuei-sung Lin public void forgetPastHistory() { 1741253e9fb0b5570ab8adaed222655a5b052aa072eRuei-sung Lin mDuration *= FORGETTING_ENUMERATOR; 1751253e9fb0b5570ab8adaed222655a5b052aa072eRuei-sung Lin mDuration /= FORGETTING_DENOMINATOR; 1761253e9fb0b5570ab8adaed222655a5b052aa072eRuei-sung Lin 1771253e9fb0b5570ab8adaed222655a5b052aa072eRuei-sung Lin for (Map.Entry<String, Long> entry : mHistogram.entrySet()) { 1781253e9fb0b5570ab8adaed222655a5b052aa072eRuei-sung Lin String key = entry.getKey(); 1791253e9fb0b5570ab8adaed222655a5b052aa072eRuei-sung Lin long value = entry.getValue(); 1801253e9fb0b5570ab8adaed222655a5b052aa072eRuei-sung Lin 1811253e9fb0b5570ab8adaed222655a5b052aa072eRuei-sung Lin value *= FORGETTING_ENUMERATOR; 1821253e9fb0b5570ab8adaed222655a5b052aa072eRuei-sung Lin value /= FORGETTING_DENOMINATOR; 1831253e9fb0b5570ab8adaed222655a5b052aa072eRuei-sung Lin 1841253e9fb0b5570ab8adaed222655a5b052aa072eRuei-sung Lin mHistogram.put(key, value); 1851253e9fb0b5570ab8adaed222655a5b052aa072eRuei-sung Lin } 1861253e9fb0b5570ab8adaed222655a5b052aa072eRuei-sung Lin } 1871253e9fb0b5570ab8adaed222655a5b052aa072eRuei-sung Lin 1881253e9fb0b5570ab8adaed222655a5b052aa072eRuei-sung Lin protected void normalizeCenter() { 1891253e9fb0b5570ab8adaed222655a5b052aa072eRuei-sung Lin double norm = 0; 1901253e9fb0b5570ab8adaed222655a5b052aa072eRuei-sung Lin for (int i = 0; i < VECTOR_LENGTH; ++i) { 1911253e9fb0b5570ab8adaed222655a5b052aa072eRuei-sung Lin norm += mCenter[i] * mCenter[i]; 1921253e9fb0b5570ab8adaed222655a5b052aa072eRuei-sung Lin } 1931253e9fb0b5570ab8adaed222655a5b052aa072eRuei-sung Lin norm = Math.sqrt(norm); 1941253e9fb0b5570ab8adaed222655a5b052aa072eRuei-sung Lin for (int i = 0; i < VECTOR_LENGTH; ++i) { 1951253e9fb0b5570ab8adaed222655a5b052aa072eRuei-sung Lin mCenter[i] /= norm; 1961253e9fb0b5570ab8adaed222655a5b052aa072eRuei-sung Lin } 1971253e9fb0b5570ab8adaed222655a5b052aa072eRuei-sung Lin } 1981253e9fb0b5570ab8adaed222655a5b052aa072eRuei-sung Lin 1991253e9fb0b5570ab8adaed222655a5b052aa072eRuei-sung Lin protected void averageCenter(double[] newCenter, long newDuration) { 2001253e9fb0b5570ab8adaed222655a5b052aa072eRuei-sung Lin double weight = ((double) mDuration) / (mDuration + newDuration); 2011253e9fb0b5570ab8adaed222655a5b052aa072eRuei-sung Lin double newWeight = 1f - weight; 2021253e9fb0b5570ab8adaed222655a5b052aa072eRuei-sung Lin 2031253e9fb0b5570ab8adaed222655a5b052aa072eRuei-sung Lin double norm = 0; 2041253e9fb0b5570ab8adaed222655a5b052aa072eRuei-sung Lin for (int i = 0; i < VECTOR_LENGTH; ++i) { 2051253e9fb0b5570ab8adaed222655a5b052aa072eRuei-sung Lin mCenter[i] = weight * mCenter[i] + newWeight * newCenter[i]; 2061253e9fb0b5570ab8adaed222655a5b052aa072eRuei-sung Lin norm += mCenter[i] * mCenter[i]; 2071253e9fb0b5570ab8adaed222655a5b052aa072eRuei-sung Lin } 2081253e9fb0b5570ab8adaed222655a5b052aa072eRuei-sung Lin norm = Math.sqrt(norm); 2091253e9fb0b5570ab8adaed222655a5b052aa072eRuei-sung Lin for (int i = 0; i < VECTOR_LENGTH; ++i) { 2101253e9fb0b5570ab8adaed222655a5b052aa072eRuei-sung Lin mCenter[i] /= norm; 2111253e9fb0b5570ab8adaed222655a5b052aa072eRuei-sung Lin } 2121253e9fb0b5570ab8adaed222655a5b052aa072eRuei-sung Lin } 213f0f78449e8ab7d63894964c54b6ef390ca9ce044Ruei-sung Lin} 214