#define VISIT_COLUMN_START_TIME_HUMAN "start_time_human" // only for debug: human readable time data:
#define VISIT_COLUMN_END_TIME_HUMAN "end_time_human" // only for debug: human readable time data:
#endif /* TIZEN_ENGINEER_MODE */
-#define VISIT_COLUMN_LOCATION_VALID "geo_valid"
-#define VISIT_COLUMN_LOCATION_LATITUDE "geo_latitude"
-#define VISIT_COLUMN_LOCATION_LONGITUDE "geo_longitude"
+#define VISIT_COLUMN_LOCATION_VALID "location_valid"
+#define VISIT_COLUMN_LOCATION_LATITUDE "location_latitude"
+#define VISIT_COLUMN_LOCATION_LONGITUDE "location_longitude"
+#define VISIT_COLUMN_LOCATION_ACCURACY "location_accuracy"
#define VISIT_COLUMN_CATEG_HOME "categ_home"
#define VISIT_COLUMN_CATEG_WORK "categ_work"
#define VISIT_COLUMN_CATEG_OTHER "categ_other"
#define WIFI_APS_MAP_COLUMN_INSERT_TIME "insert_time"
#define PLACE_TABLE "place_status_user_place"
-#define PLACE_COLUMN_CATEG_ID "type_id" // Name inconsistency: "cated_id" vs "type_id" TODO make it consistent
-#define PLACE_COLUMN_CATEG_CONFIDENCE "type_confidence"
+#define PLACE_COLUMN_CATEG_ID "categ_id"
+#define PLACE_COLUMN_CATEG_CONFIDENCE "categ_confidence"
#define PLACE_COLUMN_NAME "name"
-#define PLACE_COLUMN_LOCATION_VALID "geo_valid"
-#define PLACE_COLUMN_LOCATION_LATITUDE "geo_latitude"
-#define PLACE_COLUMN_LOCATION_LONGITUDE "geo_longitude"
+#define PLACE_COLUMN_LOCATION_VALID "location_valid"
+#define PLACE_COLUMN_LOCATION_LATITUDE "location_latitude"
+#define PLACE_COLUMN_LOCATION_LONGITUDE "location_longitude"
+#define PLACE_COLUMN_LOCATION_ACCURACY "location_accuracy"
#define PLACE_COLUMN_WIFI_APS "wifi_aps"
#define PLACE_COLUMN_CREATE_DATE "create_date"
#include <Types.h>
#include "median.h"
-ctx::num_t ctx::median(std::vector<ctx::num_t> &v)
+static bool compareFun(std::pair<double, int> &i, std::pair<double, int> &j) {
+ return (i.first < j.first);
+}
+
+double ctx::median(std::vector<double> &values, int &elemIdx, int &evenCaseElemIdx)
{
- if (v.empty()) {
+ if (values.empty()) {
_E("Median of empty set");
- return 0; // this value does not make any sense
+ return -1;
+ }
+ std::vector<std::pair<double, int>> valuesTemp;
+ for (size_t i = 0; i < values.size(); i++) {
+ valuesTemp.push_back(std::pair<double, int>(values[i], i));
+ }
+ int n = valuesTemp.size() / 2;
+ std::nth_element(valuesTemp.begin(), valuesTemp.begin() + n, valuesTemp.end(), compareFun);
+ std::pair<double, int> valuesTempN = valuesTemp[n];
+ elemIdx = valuesTempN.second;
+ if (valuesTemp.size() % 2 == 1) { //odd size
+ evenCaseElemIdx = -1;
+ return valuesTempN.first;
+ } else { // even size
+ std::nth_element(valuesTemp.begin(), valuesTemp.begin() + n - 1, valuesTemp.end());
+ evenCaseElemIdx = valuesTemp[n - 1].second;
+ return 0.5 * (valuesTempN.first + valuesTemp[n - 1].first);
+ }
+}
+
+ctx::Location ctx::medianLocation(std::vector<double> &latitudes, std::vector<double> &longitudes, std::vector<double> &accuracy)
+{
+ ctx::Location location;
+ if (latitudes.empty() || latitudes.size() != longitudes.size() || latitudes.size() != accuracy.size()) {
+ _E("Incorrect input vectors size");
+ return location;
+ }
+ int idx;
+ int additionalIdx;
+ location.latitude = median(latitudes, idx, additionalIdx);
+ double latitudeAccuracy = accuracy[idx];
+ if (additionalIdx >= 0) {
+ latitudeAccuracy = 0.5 * (latitudeAccuracy + accuracy[additionalIdx]);
}
- size_t n = v.size() / 2;
- std::nth_element(v.begin(), v.begin() + n, v.end());
- num_t vn = v[n];
- if (v.size() % 2 == 1) {
- return vn;
- } else {
- std::nth_element(v.begin(), v.begin() + n - 1, v.end());
- return 0.5 * (vn + v[n - 1]);
+ location.longitude = median(longitudes, idx, additionalIdx);
+ double longitudeAccuracy = accuracy[idx];
+ if (additionalIdx >= 0) {
+ longitudeAccuracy = 0.5 * (longitudeAccuracy + accuracy[additionalIdx]);
}
+ location.accuracy = 0.5 * (latitudeAccuracy + longitudeAccuracy);
+ return location;
}
namespace ctx {
- num_t median(std::vector<num_t> &values); // caution: the input vector will be sorted
+ double median(std::vector<double> &values, int &elemIdx, int &evenCaseElemIdx);
+ ctx::Location medianLocation(std::vector<double> &latitudes, std::vector<double> &longitudes, std::vector<double> &accuracy);
} /* namespace ctx */
num_t maxScore = 0.0;
for (PlaceCategId categId : categIds) {
std::vector<num_t> categVector = __categVectorFromVisits(visits, categId);
- num_t score = median(categVector);
+ int i, j;
+ num_t score = median(categVector, i, j);
sumScore += score;
if (score > maxScore) {
maxScore = score;
VISIT_COLUMN_WIFI_APS ", "\
VISIT_COLUMN_LOCATION_VALID ", "\
VISIT_COLUMN_LOCATION_LATITUDE ", "\
- VISIT_COLUMN_LOCATION_LONGITUDE ", " \
+ VISIT_COLUMN_LOCATION_LONGITUDE ", "\
+ VISIT_COLUMN_LOCATION_ACCURACY ", "\
VISIT_COLUMN_CATEG_HOME ", "\
VISIT_COLUMN_CATEG_WORK ", "\
VISIT_COLUMN_CATEG_OTHER \
PLACE_COLUMN_NAME ", "\
PLACE_COLUMN_LOCATION_VALID ", "\
PLACE_COLUMN_LOCATION_LATITUDE ", "\
- PLACE_COLUMN_LOCATION_LONGITUDE ", " \
+ PLACE_COLUMN_LOCATION_LONGITUDE ", "\
+ PLACE_COLUMN_LOCATION_ACCURACY ", "\
PLACE_COLUMN_WIFI_APS ", "\
PLACE_COLUMN_CREATE_DATE \
" FROM " PLACE_TABLE
PLACE_COLUMN_LOCATION_VALID " INTEGER, "\
PLACE_COLUMN_LOCATION_LATITUDE " REAL, "\
PLACE_COLUMN_LOCATION_LONGITUDE " REAL, "\
+ PLACE_COLUMN_LOCATION_ACCURACY " REAL, "\
PLACE_COLUMN_WIFI_APS " STRING, "\
PLACE_COLUMN_CREATE_DATE " timestamp"
place.locationValid = (bool) locationValidInt;
row.get(NULL, PLACE_COLUMN_LOCATION_LATITUDE, &(place.location.latitude));
row.get(NULL, PLACE_COLUMN_LOCATION_LONGITUDE, &(place.location.longitude));
+ row.get(NULL, PLACE_COLUMN_LOCATION_ACCURACY, &(place.location.accuracy));
}
void ctx::PlacesDetector::__placeWifiAPsFromJson(Json &row, ctx::Place &place)
void ctx::PlacesDetector::__mergeLocation(const Visits &visits, Place &place)
{
- place.locationValid = false;
std::vector<double> latitudes;
std::vector<double> longitudes;
+ std::vector<double> accuracy;
+ place.locationValid = false;
for (const Visit& visit : visits) {
if (visit.locationValid) {
latitudes.push_back(visit.location.latitude);
longitudes.push_back(visit.location.longitude);
+ accuracy.push_back(visit.location.accuracy);
place.locationValid = true;
}
}
if (place.locationValid) {
- place.location.latitude = median(latitudes);
- place.location.longitude = median(longitudes);
+ place.location = medianLocation(latitudes, longitudes, accuracy);
+ _D("place location set: lat=%.8f, lon=%.8f, acc=%.8f",
+ place.location.latitude,
+ place.location.longitude,
+ place.location.accuracy);
+ } else {
+ _D("place location not set");
}
}
data.set(NULL, PLACE_COLUMN_LOCATION_VALID, place.locationValid);
data.set(NULL, PLACE_COLUMN_LOCATION_LATITUDE, place.location.latitude);
data.set(NULL, PLACE_COLUMN_LOCATION_LONGITUDE, place.location.longitude);
+ data.set(NULL, PLACE_COLUMN_LOCATION_ACCURACY, place.location.accuracy);
std::string wifiAps;
for (std::pair<std::string, std::string> ap : place.wifiAps) {
wifiAps.append(ap.first);
VISIT_COLUMN_LOCATION_VALID " INTEGER, "\
VISIT_COLUMN_LOCATION_LATITUDE " REAL, "\
VISIT_COLUMN_LOCATION_LONGITUDE " REAL, "\
+ VISIT_COLUMN_LOCATION_ACCURACY " REAL, "\
VISIT_COLUMN_CATEG_HOME " REAL, "\
VISIT_COLUMN_CATEG_WORK " REAL, "\
VISIT_COLUMN_CATEG_OTHER " REAL"
VISIT_COLUMN_LOCATION_VALID " INTEGER, "\
VISIT_COLUMN_LOCATION_LATITUDE " REAL, "\
VISIT_COLUMN_LOCATION_LONGITUDE " REAL, "\
+ VISIT_COLUMN_LOCATION_ACCURACY " REAL, "\
VISIT_COLUMN_CATEG_HOME " REAL, "\
VISIT_COLUMN_CATEG_WORK " REAL, "\
VISIT_COLUMN_CATEG_OTHER " REAL"
void ctx::VisitDetector::__putLocationToVisit(ctx::Visit &visit)
{
- // TODO: remove small accuracy locations from vectors?
+ // TODO: filter out small accuracy locations?
std::vector<double> latitudes;
std::vector<double> longitudes;
+ std::vector<double> accuracy;
visit.locationValid = false;
- for (LocationEvent location : __locationEvents) {
+ for (LocationEvent &location : __locationEvents) {
if (location.timestamp >= __entranceTime && location.timestamp <= __departureTime) {
latitudes.push_back(location.coordinates.latitude);
longitudes.push_back(location.coordinates.longitude);
+ accuracy.push_back(location.coordinates.accuracy);
visit.locationValid = true;
}
}
if (visit.locationValid) {
- visit.location.latitude = median(latitudes);
- visit.location.longitude = median(longitudes);
- _D("visit location set: lat=%.8f, lon=%.8f", visit.location.latitude, visit.location.longitude);
+ visit.location = medianLocation(latitudes, longitudes, accuracy);
+ _D("visit location set: lat=%.8f, lon=%.8f, acc=%.8f",
+ visit.location.latitude,
+ visit.location.longitude,
+ visit.location.accuracy);
} else {
_D("visit location not set");
}
data.set(NULL, VISIT_COLUMN_LOCATION_VALID, visit.locationValid);
data.set(NULL, VISIT_COLUMN_LOCATION_LATITUDE, visit.location.latitude);
data.set(NULL, VISIT_COLUMN_LOCATION_LONGITUDE, visit.location.longitude);
+ data.set(NULL, VISIT_COLUMN_LOCATION_ACCURACY, visit.location.accuracy);
data.set(NULL, VISIT_COLUMN_START_TIME, static_cast<int>(visit.interval.start));
data.set(NULL, VISIT_COLUMN_END_TIME, static_cast<int>(visit.interval.end));