* Copyright (C) 2022 Huawei Device Co., Ltd.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "location.h"
#include <parcel.h>
#include <string>
#include "string_ex.h"
#include <iostream>
#include <cmath>
namespace OHOS {
namespace Location {
static constexpr double MIN_LATITUDE = -90.0;
static constexpr double MIN_LONGITUDE = -180.0;
static constexpr int MAX_POI_ARRAY_SIZE = 20;
static constexpr double MAX_LATITUDE = 90.0;
static constexpr double MAX_LONGITUDE = 180.0;
const double PI = 3.1415926;
const double DEGREE_PI = 180.0;
const double POW_PARAMETER_TOW = 2;
const double NUM_DOUBLE = 2;
const double EARTH_SEMI_AXIS = 6378137.0;
const double EARTH_FLATTENING = 6356752.3142;
const double EARTH_SEMI_MINOR = (EARTH_SEMI_AXIS - EARTH_FLATTENING) / EARTH_SEMI_AXIS;
Location::Location()
{
latitude_ = MIN_LATITUDE - 1;
longitude_ = MIN_LONGITUDE - 1;
altitude_ = 0.0;
accuracy_ = 0.0;
speed_ = 0.0;
direction_ = 0.0;
timeStamp_ = 0;
timeSinceBoot_ = 0;
additionSize_ = 0;
isFromMock_ = false;
isSystemApp_ = 0;
floorNo_ = 0;
floorAccuracy_ = 0.0;
altitudeAccuracy_ = 0.0;
speedAccuracy_ = 0.0;
directionAccuracy_ = 0.0;
uncertaintyOfTimeSinceBoot_ = 0;
locationSourceType_ = 0;
uuid_ = "";
fieldValidity_ = 0;
}
Location::Location(const Location& location)
{
latitude_ = location.GetLatitude();
longitude_ = location.GetLongitude();
altitude_ = location.GetAltitude();
accuracy_ = location.GetAccuracy();
speed_ = location.GetSpeed();
direction_ = location.GetDirection();
timeStamp_ = location.GetTimeStamp();
timeSinceBoot_ = location.GetTimeSinceBoot();
floorNo_ = location.GetFloorNo();
floorAccuracy_ = location.GetFloorAccuracy();
additions_ = location.GetAdditions();
additionsMap_ = location.GetAdditionsMap();
additionSize_ = location.GetAdditionSize();
isFromMock_ = location.GetIsFromMock();
isSystemApp_ = location.GetIsSystemApp();
altitudeAccuracy_ = location.GetAltitudeAccuracy();
speedAccuracy_ = location.GetSpeedAccuracy();
directionAccuracy_ = location.GetDirectionAccuracy();
uncertaintyOfTimeSinceBoot_ = location.GetUncertaintyOfTimeSinceBoot();
locationSourceType_ = location.GetLocationSourceType();
uuid_ = location.GetUuid();
fieldValidity_ = location.GetFieldValidity();
poiInfo_ = location.GetPoiInfo();
}
void Location::ReadFromParcel(Parcel& parcel)
{
latitude_ = parcel.ReadDouble();
longitude_ = parcel.ReadDouble();
altitude_ = parcel.ReadDouble();
accuracy_ = parcel.ReadDouble();
speed_ = parcel.ReadDouble();
direction_ = parcel.ReadDouble();
timeStamp_ = parcel.ReadInt64();
timeSinceBoot_ = parcel.ReadInt64();
additionSize_ = parcel.ReadInt64();
std::vector<std::u16string> additions;
parcel.ReadString16Vector(&additions);
isFromMock_ = parcel.ReadBool();
isSystemApp_ = parcel.ReadInt32();
altitudeAccuracy_ = parcel.ReadDouble();
speedAccuracy_ = parcel.ReadDouble();
directionAccuracy_ = parcel.ReadDouble();
uncertaintyOfTimeSinceBoot_ = parcel.ReadInt64();
locationSourceType_ = parcel.ReadInt32();
uuid_ = Str16ToStr8(parcel.ReadString16());
fieldValidity_ = parcel.ReadInt32();
VectorString16ToVectorString8(additions);
poiInfo_ = ReadPoiInfoFromParcel(parcel);
}
void Location::VectorString16ToVectorString8(const std::vector<std::u16string>& additions)
{
for (auto &addition : additions) {
auto additionString = Str16ToStr8(addition);
if (additionString.size() == 0) {
continue;
}
additions_.push_back(additionString);
auto pos = additionString.find(":");
auto key = additionString.substr(0, pos);
auto value = additionString.substr(pos + 1, additionString.size() - 1);
additionsMap_[key] = value;
}
}
std::shared_ptr<Location> Location::UnmarshallingShared(Parcel& parcel)
{
std::shared_ptr<Location> location = std::make_shared<Location>();
location->ReadFromParcel(parcel);
return location;
}
Location* Location::Unmarshalling(Parcel& parcel)
{
auto location = new Location();
location->ReadFromParcel(parcel);
return location;
}
std::unique_ptr<Location> Location::UnmarshallingMakeUnique(Parcel& parcel)
{
std::unique_ptr<Location> location = std::make_unique<Location>();
location->ReadFromParcel(parcel);
return location;
}
bool Location::Marshalling(Parcel& parcel) const
{
auto additions = VectorString8ToVectorString16();
return parcel.WriteDouble(latitude_) &&
parcel.WriteDouble(longitude_) &&
parcel.WriteDouble(altitude_) &&
parcel.WriteDouble(accuracy_) &&
parcel.WriteDouble(speed_) &&
parcel.WriteDouble(direction_) &&
parcel.WriteInt64(timeStamp_) &&
parcel.WriteInt64(timeSinceBoot_) &&
parcel.WriteInt64(additionSize_) &&
parcel.WriteString16Vector(additions) &&
parcel.WriteBool(isFromMock_) &&
parcel.WriteInt32(isSystemApp_) &&
parcel.WriteDouble(altitudeAccuracy_) &&
parcel.WriteDouble(speedAccuracy_) &&
parcel.WriteDouble(directionAccuracy_) &&
parcel.WriteInt64(uncertaintyOfTimeSinceBoot_) &&
parcel.WriteInt32(locationSourceType_) &&
parcel.WriteString16(Str8ToStr16(uuid_)) &&
parcel.WriteInt32(fieldValidity_) &&
WritePoiInfoToParcel(poiInfo_, parcel);
}
std::vector<std::u16string> Location::VectorString8ToVectorString16() const
{
std::vector<std::u16string> additions;
for (auto &addition : additions_) {
auto additionString = Str8ToStr16(addition);
additions.push_back(additionString);
}
return additions;
}
bool Location::WritePoiInfoToParcel(const PoiInfo& data, Parcel& parcel)
{
bool parcelState = true;
parcelState = parcelState && parcel.WriteUint64(data.timestamp);
parcelState = parcelState && parcel.WriteUint32(data.poiArray.size());
for (const auto& poi : data.poiArray) {
parcelState = parcelState && parcel.WriteString(poi.id);
parcelState = parcelState && parcel.WriteDouble(poi.confidence);
parcelState = parcelState && parcel.WriteString(poi.name);
parcelState = parcelState && parcel.WriteDouble(poi.latitude);
parcelState = parcelState && parcel.WriteDouble(poi.longitude);
parcelState = parcelState && parcel.WriteString(poi.administrativeArea);
parcelState = parcelState && parcel.WriteString(poi.subAdministrativeArea);
parcelState = parcelState && parcel.WriteString(poi.locality);
parcelState = parcelState && parcel.WriteString(poi.subLocality);
parcelState = parcelState && parcel.WriteString(poi.address);
parcelState = parcelState && parcel.WriteString(poi.additionalInfo);
}
return parcelState;
}
PoiInfo Location::ReadPoiInfoFromParcel(Parcel& parcel)
{
PoiInfo data;
data.timestamp = parcel.ReadUint64();
uint32_t size = parcel.ReadUint32();
if (size > MAX_POI_ARRAY_SIZE) {
size = MAX_POI_ARRAY_SIZE;
}
data.poiArray.resize(size);
for (auto& poi : data.poiArray) {
poi.id = parcel.ReadString();
poi.confidence = parcel.ReadDouble();
poi.name = parcel.ReadString();
poi.latitude = parcel.ReadDouble();
poi.longitude = parcel.ReadDouble();
poi.administrativeArea = parcel.ReadString();
poi.subAdministrativeArea = parcel.ReadString();
poi.locality = parcel.ReadString();
poi.subLocality = parcel.ReadString();
poi.address = parcel.ReadString();
poi.additionalInfo = parcel.ReadString();
}
return data;
}
void Location::AddNlpStatusFromParcel(Parcel& parcel)
{
additionsMap_["cellId"] = Str16ToStr8(parcel.ReadString16());
additionsMap_["locateType"] = Str16ToStr8(parcel.ReadString16());
}
void Location::RemoveNlpStatus()
{
additionsMap_.erase("cellId");
additionsMap_.erase("locateType");
}
std::string Location::ToString() const
{
std::string str =
", altitude : " + std::to_string(altitude_) +
", accuracy : " + std::to_string(accuracy_) +
", speed : " + std::to_string(speed_) +
", direction : " + std::to_string(direction_) +
", timeStamp : " + std::to_string(timeStamp_) +
", timeSinceBoot : " + std::to_string(timeSinceBoot_) +
", additionSize : " + std::to_string(additionSize_) +
", isFromMock : " + std::to_string(isFromMock_) +
", isSystemApp : " + std::to_string(isSystemApp_) +
", altitudeAccuracy : " + std::to_string(altitudeAccuracy_) +
", speedAccuracy : " + std::to_string(speedAccuracy_) +
", directionAccuracy : " + std::to_string(directionAccuracy_) +
", uncertaintyOfTimeSinceBoot : " + std::to_string(uncertaintyOfTimeSinceBoot_) +
", locationSourceType : " + std::to_string(locationSourceType_) +
", uuid : " + uuid_ +
", fieldValidity : " + std::to_string(fieldValidity_);
return str;
}
bool Location::LocationEqual(const std::unique_ptr<Location>& location)
{
if (location == nullptr) {
return false;
}
if (DoubleEqual(this->GetLatitude(), location->GetLatitude()) &&
DoubleEqual(this->GetLongitude(), location->GetLongitude()) &&
DoubleEqual(this->GetAltitude(), location->GetAltitude()) &&
DoubleEqual(this->GetAccuracy(), location->GetAccuracy()) &&
DoubleEqual(this->GetSpeed(), location->GetSpeed()) &&
DoubleEqual(this->GetDirection(), location->GetDirection()) &&
this->GetTimeStamp() == location->GetTimeStamp() &&
this->GetTimeSinceBoot() == location->GetTimeSinceBoot() &&
this->GetIsFromMock() == location->GetIsFromMock()) {
return true;
}
return false;
}
bool Location::AdditionEqual(const std::unique_ptr<Location>& location)
{
if (location == nullptr) {
return false;
}
std::vector<std::string> additionA = this->GetAdditions();
std::vector<std::string> additionB = location->GetAdditions();
if (additionA.size() != additionB.size()) {
return false;
}
for (size_t i = 0; i < additionA.size(); i++) {
if (additionA[i].compare(additionB[i]) != 0) {
return false;
}
}
return true;
}
bool Location::isValidLatitude(double latitude)
{
return latitude >= MIN_LATITUDE && latitude <= MAX_LATITUDE;
}
bool Location::isValidLongitude(double longitude)
{
return longitude >= MIN_LONGITUDE && longitude <= MAX_LONGITUDE;
}
double Location::GetDistanceBetweenLocations(const double lat1, const double lon1, const double lat2, const double lon2)
{
double radLat1 = lat1 * PI / DEGREE_PI;
double radLat2 = lat2 * PI / DEGREE_PI;
double radLon1 = lon1 * PI / DEGREE_PI;
double radLon2 = lon2 * PI / DEGREE_PI;
double deltaLon = radLon2 - radLon1;
double reducedLat1 = atan((1 - EARTH_SEMI_MINOR) * tan(radLat1));
double reducedLat2 = atan((1 - EARTH_SEMI_MINOR) * tan(radLat2));
double sinReducedLat1 = sin(reducedLat1);
double cosReducedLat1 = cos(reducedLat1);
double sinReducedLat2 = sin(reducedLat2);
double cosReducedLat2 = cos(reducedLat2);
double lambda = deltaLon;
double lambdaP = 100;
double iterLimit = 20;
double sinAlpha = 0.0;
double cosSqAlpha = 0.0;
double sinSigma = 0.0;
double cos2SigmaM = 0.0;
double cosSigma = 0.0;
double sigma = 0.0;
double sinLambda = 0.0;
double cosLambda = 0.0;
for (int iter = 0; iter < iterLimit; iter++) {
sinLambda = sin(lambda);
cosLambda = cos(lambda);
sinSigma = sqrt(pow(cosReducedLat2 * sinLambda, POW_PARAMETER_TOW) +
pow(cosReducedLat1 * sinReducedLat2 - sinReducedLat1 * cosReducedLat2 * cosLambda, POW_PARAMETER_TOW));
if (sinSigma == 0.0) {
return 0;
}
cosSigma = sinReducedLat1 * sinReducedLat2 + cosReducedLat1 * cosReducedLat2 * cosLambda;
sigma = atan2(sinSigma, cosSigma);
sinAlpha = cosReducedLat1 * cosReducedLat2 * sinLambda / sinSigma;
cosSqAlpha = 1 - sinAlpha * sinAlpha;
cos2SigmaM = (cosSqAlpha != 0.0) ? (cosSigma - NUM_DOUBLE * sinReducedLat1 * sinReducedLat2 / cosSqAlpha) : 0;
double correction = EARTH_SEMI_MINOR / 16 * cosSqAlpha * (4 + EARTH_SEMI_MINOR * (4 - 3 * cosSqAlpha));
lambdaP = lambda;
lambda = deltaLon + (1 - correction) * EARTH_SEMI_MINOR * sinAlpha *
(sigma + correction * sinSigma *
(cos2SigmaM + correction * cosSigma * (-1 + NUM_DOUBLE * pow(cos2SigmaM, POW_PARAMETER_TOW))));
if (fabs(lambda - lambdaP) < 1e-12) {
break;
}
}
double uSquared = cosSqAlpha * (EARTH_SEMI_AXIS * EARTH_SEMI_AXIS - EARTH_FLATTENING * EARTH_FLATTENING) /
(EARTH_FLATTENING * EARTH_FLATTENING);
double highOrderCorrection = 1 + uSquared / 16384 * (4096 + uSquared * (-768 + uSquared * (320 - 175 * uSquared)));
double highOrderTerm = uSquared / 1024 * (256 + uSquared * (-128 + uSquared * (74 - 47 * uSquared)));
double deltaSigma = highOrderTerm * sinSigma *
(cos2SigmaM + highOrderTerm / 4 * (cosSigma * (-1 + 2 * pow(cos2SigmaM, POW_PARAMETER_TOW)) -
highOrderTerm / 6 * cos2SigmaM * (-3 + 4 * pow(sinSigma, POW_PARAMETER_TOW)) *
(-3 + 4 * pow(cos2SigmaM, POW_PARAMETER_TOW))));
double distance = EARTH_FLATTENING * highOrderCorrection * (sigma - deltaSigma);
return distance;
}
bool Location::DoubleEqual(double a, double b)
{
if (fabs(a - b) < 1e-6) {
return true;
} else {
return false;
}
}
}
}