Files
pilotclient/src/blackmisc/pq/angle.cpp
Mat Sutcliffe 40362c1f4a Use sprintf to decompose the degrees, minutes, and seconds
Instead of repeatedly multiplying by 100, which can cause
epsilon errors to grow to too significant magnitudes.
2020-12-08 21:02:19 +00:00

154 lines
4.9 KiB
C++

/* Copyright (C) 2013
* swift project Community / Contributors
*
* This file is part of swift project. It is subject to the license terms in the LICENSE file found in the top-level
* directory of this distribution. No part of swift project, including this file, may be copied, modified, propagated,
* or distributed except according to the terms contained in the LICENSE file.
*/
#include "blackmisc/pq/angle.h"
#include "blackmisc/iconlist.h"
#include "blackmisc/icons.h"
#include "blackmisc/math/mathutils.h"
#include <cmath>
using namespace BlackMisc::Math;
namespace BlackMisc
{
namespace PhysicalQuantities
{
CAngle::CAngle(int degrees, int minutes, double seconds) :
CPhysicalQuantity(
degrees + minutes / 100.0 + seconds / 10000.0,
CAngleUnit::sexagesimalDeg())
{
Q_ASSERT_X((degrees >= 0 && minutes >= 0 && seconds >= 0) ||
(degrees <= 0 && minutes <= 0 && seconds <= 0), Q_FUNC_INFO, "Same sign required");
}
CAngle::CAngle(int degrees, double minutes) :
CPhysicalQuantity(
degrees + minutes / 100.0,
CAngleUnit::sexagesimalDeg())
{
Q_ASSERT_X((degrees >= 0 && minutes >= 0) || (degrees <= 0 && minutes <= 0),
Q_FUNC_INFO, "Same sign required");
}
void CAngle::unifySign(int degrees, int &minutes, double &seconds)
{
minutes = std::copysign(minutes, degrees == 0 ? minutes : degrees);
seconds = std::copysign(seconds, degrees == 0 ? minutes : degrees);
}
void CAngle::unifySign(int degrees, int &minutes)
{
if (degrees == 0) { return; }
minutes = std::copysign(minutes, degrees);
}
CIcon CAngle::toIcon() const
{
CIcon i = CIcon::iconByIndex(CIcons::StandardIconArrowMediumNorth16);
i.setRotation(value(CAngleUnit::deg()));
return i;
}
CAngle::DegMinSecFractionalSec CAngle::asSexagesimalDegMinSec(bool range180Degrees) const
{
double dms = this->value(CAngleUnit::sexagesimalDeg());
if (range180Degrees)
{
dms = std::fmod(dms + 180.0, 360.0);
dms += (dms < 0) ? 180.0 : -180.0;
}
DegMinSecFractionalSec values;
if (dms < 0)
{
values.sign = -1;
dms *= -1.0;
}
char chars[16];
std::sprintf(chars, "%014.10f", dms); // 000.0000000000
values.deg = stringToInt(chars, chars + 3);
values.min = stringToInt(chars + 4, chars + 6);
values.sec = stringToInt(chars + 6, chars + 8);
values.fractionalSec = stringToInt(chars + 8, chars + 14) / 1000000.0;
return values;
}
double CAngle::piFactor() const
{
return Math::CMathUtils::round(this->value(CAngleUnit::rad()) / CMathUtils::PI(), 6);
}
const double &CAngle::PI()
{
return CMathUtils::PI();
}
double CAngle::sin() const
{
return std::sin(this->value(CAngleUnit::rad()));
}
double CAngle::cos() const
{
return std::cos(this->value(CAngleUnit::rad()));
}
double CAngle::tan() const
{
return std::tan(this->value(CAngleUnit::rad()));
}
void CAngle::normalizeToPlusMinus180Degrees()
{
const double v = normalizeDegrees180(this->value(CAngleUnit::deg()));
const CAngleUnit u = this->getUnit();
*this = CAngle(v, CAngleUnit::deg());
this->switchUnit(u);
}
void CAngle::normalizeTo360Degrees()
{
const double v = normalizeDegrees360(this->value(CAngleUnit::deg()));
const CAngleUnit u = this->getUnit();
*this = CAngle(v, CAngleUnit::deg());
this->switchUnit(u);
}
CAngle CAngle::normalizedToPlusMinus180Degrees() const
{
CAngle copy(*this);
copy.normalizeToPlusMinus180Degrees();
return copy;
}
CAngle CAngle::normalizedTo360Degrees() const
{
CAngle copy(*this);
copy.normalizeTo360Degrees();
return copy;
}
double CAngle::normalizeDegrees180(double degrees, int roundDigits)
{
double d = CMathUtils::normalizeDegrees360(degrees + 180.0) - 180.0;
if (d <= -180.0) { d = 180.0; } // -180 -> 180
return roundDigits < 0 ? d : CMathUtils::round(d, roundDigits);
}
double CAngle::normalizeDegrees360(double degrees, int roundDigits)
{
const double d = CMathUtils::normalizeDegrees360(degrees);
return roundDigits < 0 ? d : CMathUtils::round(d, roundDigits);
}
} // ns
} // ns