Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Added functions in arithmetic #188

Open
wants to merge 2 commits into
base: develop
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
163 changes: 129 additions & 34 deletions include/boost/astronomy/coordinate/arithmetic.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -21,15 +21,19 @@ file License.txt or copy at https://www.boost.org/LICENSE_1_0.txt)
#include <boost/geometry/core/cs.hpp>
#include <boost/units/conversion.hpp>

#include <boost/numeric/ublas/io.hpp>
#include <boost/numeric/ublas/matrix.hpp>

#include <boost/astronomy/coordinate/rep/base_representation.hpp>
#include <boost/astronomy/coordinate/rep/cartesian_representation.hpp>
#include <boost/astronomy/coordinate/rep/representation.hpp>
#include <boost/astronomy/coordinate/diff/differential.hpp>

namespace boost { namespace astronomy { namespace coordinate {

namespace bg = boost::geometry;
namespace bu = boost::units;
using namespace boost::numeric::ublas;

namespace boost { namespace astronomy { namespace coordinate {

//!Returns the cross product of cartesian_representation(representation1) and representation2
template
Expand Down Expand Up @@ -283,6 +287,40 @@ auto dot(Representation1 const& representation1, Representation2 const& represen
}


//! Returns scalar product of the cartesian vector with a factor
template <typename ...Args>
cartesian_representation<Args...>
multiply(cartesian_representation<Args...> const& vector, double factor)
{
bg::model::point
<
typename cartesian_representation<Args...>::type,
3,
bg::cs::cartesian
> tempPoint;

bg::set<0>(tempPoint, vector.get_x().value() * factor);
bg::set<1>(tempPoint, vector.get_y().value() * factor);
bg::set<2>(tempPoint, vector.get_z().value() * factor);

return cartesian_representation<Args...>(tempPoint);
}


//! Returns scalar product of given vector other than cartesian with a factor
template <typename Coordinate>
auto multiply(Coordinate const& vector, double factor)
{
Coordinate tempVector;

tempVector.set_lat(vector.get_lat());
tempVector.set_lon(vector.get_lon());
tempVector.set_dist(vector.get_dist() * factor);

return tempVector;
}


//! Returns magnitude of the cartesian vector
template
<
Expand Down Expand Up @@ -330,42 +368,13 @@ auto magnitude(Coordinate const& vector)
}


//! Returns the unit vector of vector given
template <typename ...Args>
cartesian_representation<Args...>
unit_vector(cartesian_representation<Args...> const& vector)
{
bg::model::point
<
typename cartesian_representation<Args...>::type,
3,
bg::cs::cartesian
> tempPoint;
auto mag = magnitude(vector); //magnitude of vector

//performing calculations to find unit vector
bg::set<0>(tempPoint, vector.get_x().value() / mag.value());
bg::set<1>(tempPoint,
vector.get_y().value() /
static_cast<typename cartesian_representation<Args...>::quantity2>(mag).value());
bg::set<2>(tempPoint,
vector.get_z().value() /
static_cast<typename cartesian_representation<Args...>::quantity3>(mag).value());

return cartesian_representation<Args...>(tempPoint);
}

//! Returns unit vector of given vector other than Cartesian
//! Returns unit vector of given vector
template <typename Coordinate>
auto unit_vector(Coordinate const& vector)
{
Coordinate tempVector;

tempVector.set_lat(vector.get_lat());
tempVector.set_lon(vector.get_lon());
tempVector.set_dist(1.0 * typename Coordinate::quantity3::unit_type());
auto mag = magnitude(vector); //magnitude of vector

return tempVector;
return multiply(vector, 1/mag.value());
}


Expand Down Expand Up @@ -427,6 +436,64 @@ Representation1 sum
}


//! Returns difference of representation1 and representation2
template<typename Representation1, typename Representation2>
Representation1 difference
(
Representation1 const& representation1,
Representation2 const& representation2
)
{
/*!both the coordinates/vector are first converted into
cartesian coordinate system then difference of cartesian
vectors is converted into the type of first argument and returned*/

/*checking types if it is not subclass of
base_representaion then compile time erorr is generated*/
//BOOST_STATIC_ASSERT_MSG((boost::astronomy::detail::is_base_template_of
// <
// boost::astronomy::coordinate::base_representation,
// Representation1
// >::value),
// "First argument type is expected to be a representation class");
//BOOST_STATIC_ASSERT_MSG((boost::astronomy::detail::is_base_template_of
// <
// boost::astronomy::coordinate::base_representation,
// Representation2
// >::value),
// "Second argument type is expected to be a representation class");

/*converting both coordinates/vector into cartesian system*/
bg::model::point
<
typename std::conditional
<
sizeof(typename Representation2::type) >=
sizeof(typename Representation1::type),
typename Representation2::type,
typename Representation1::type
>::type,
3,
bg::cs::cartesian
> result;

auto cartesian1 = make_cartesian_representation(representation1);
auto cartesian2 = make_cartesian_representation(representation2);

typedef decltype(cartesian1) cartesian1_type;

//performing calculation to find the sum
bg::set<0>(result, (cartesian1.get_x().value() -
static_cast<typename cartesian1_type::quantity1>(cartesian2.get_x()).value()));
bg::set<1>(result, (cartesian1.get_y().value() -
static_cast<typename cartesian1_type::quantity2>(cartesian2.get_y()).value()));
bg::set<2>(result, (cartesian1.get_z().value() -
static_cast<typename cartesian1_type::quantity3>(cartesian2.get_z()).value()));

return Representation1(result);
}


//! Returns mean of representation1 and representation2
template<typename Representation1, typename Representation2>
Representation1 mean
Expand Down Expand Up @@ -476,5 +543,33 @@ Representation1 mean
return Representation1(result);
}


//! Returns multiplication of a matrix with the cartesian representation
template <typename ...Args, typename MatrixType = double>
cartesian_representation<Args...>
matrix_multiply(cartesian_representation<Args...> const& representation, matrix<MatrixType> mul)
{
matrix<double> vec = matrix<double>(3,1);

vec(0,0) = representation.get_x().value();
vec(1,0) = representation.get_y().value();
vec(2,0) = representation.get_z().value();

vec = prod(mul, vec);

bg::model::point
<
typename cartesian_representation<Args...>::type,
3,
bg::cs::cartesian
> ans;
bg::set<0>(ans, vec(0,0));
bg::set<1>(ans, vec(1,0));
bg::set<2>(ans, vec(2,0));

return cartesian_representation<Args...>(ans);
}


}}} // namespace boost::astronomy::coordinate
#endif // !BOOST_ASTRONOMY_COORDINATE_ARITHMETIC_HPP
57 changes: 57 additions & 0 deletions test/coordinate/cartesian_representation.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -245,6 +245,22 @@ BOOST_AUTO_TEST_CASE(cartesian_representation_dot_product)
<bu::multiply_typeof_helper<decltype(si::milli*meters), si::length>::type>>::value));
}

BOOST_AUTO_TEST_CASE(cartesian_representation_scalar_multiplication)
{
auto point1 = make_cartesian_representation(25.0 * meter, 36.0 * si::centi * meter, 90.0 * si::kilo * meter);

auto result = boost::astronomy::coordinate::multiply(point1, 2);

BOOST_CHECK_CLOSE(result.get_x().value(), 50.0, 0.001);
BOOST_CHECK_CLOSE(result.get_y().value(), 72.0, 0.001);
BOOST_CHECK_CLOSE(result.get_z().value(), 180.0, 0.001);

//checking whether quantity stored is as expected or not
BOOST_TEST((std::is_same<decltype(result.get_x()), quantity<si::length>>::value));
BOOST_TEST((std::is_same<decltype(result.get_y()), quantity<decltype(si::centi*meter)>>::value));
BOOST_TEST((std::is_same<decltype(result.get_z()), quantity<decltype(si::kilo*meter)>>::value));
}

BOOST_AUTO_TEST_CASE(cartesian_representation_unit_vector)
{
auto point1 = make_cartesian_representation(25.0*meter, 36.0*meter, 90.0*meter);
Expand Down Expand Up @@ -294,6 +310,25 @@ BOOST_AUTO_TEST_CASE(cartesian_representation_sum)
BOOST_TEST((std::is_same<decltype(result.get_z()), quantity<si::length>>::value));
}

BOOST_AUTO_TEST_CASE(cartesian_representation_difference)
{
auto point1 = make_cartesian_representation
(10.0 * meter, 20.0 * si::kilo * meters, 30.0 * meter);
auto point2 = make_cartesian_representation
(50.0 * si::centi * meter, 60.0 * meter, 30.0 * meter);

auto result = boost::astronomy::coordinate::difference(point1, point2);

BOOST_CHECK_CLOSE(result.get_x().value(), 9.5, 0.001);
BOOST_CHECK_CLOSE(result.get_y().value(), 19.94, 0.001);
BOOST_CHECK_CLOSE(result.get_z().value(), 0, 0.001);

//checking whether quantity stored is as expected or not
BOOST_TEST((std::is_same<decltype(result.get_x()), quantity<si::length>>::value));
BOOST_TEST((std::is_same<decltype(result.get_y()), quantity<decltype(si::kilo*meter)>>::value));
BOOST_TEST((std::is_same<decltype(result.get_z()), quantity<si::length>>::value));
}

BOOST_AUTO_TEST_CASE(cartesian_representation_mean)
{
auto point1 = make_cartesian_representation
Expand All @@ -313,4 +348,26 @@ BOOST_AUTO_TEST_CASE(cartesian_representation_mean)
BOOST_TEST((std::is_same<decltype(result.get_z()), quantity<si::length>>::value));
}

BOOST_AUTO_TEST_CASE(cartesian_representation_matrix_multiplication)
{
auto point = make_cartesian_representation
(10.0 * meter, 20.0 * si::kilo * meters, 30.0 * si::centi * meter);

matrix<double> m(3, 3);
for (unsigned i = 0; i < m.size1(); ++i)
for (unsigned j = 0; j < m.size2(); ++j)
m(i, j) = 3 * i + j;

auto result = boost::astronomy::coordinate::matrix_multiply(point, m);

BOOST_CHECK_CLOSE(result.get_x().value(), 80.0, 0.001);
BOOST_CHECK_CLOSE(result.get_y().value(), 260.0, 0.001);
BOOST_CHECK_CLOSE(result.get_z().value(), 440.0, 0.001);

//checking whether quantity stored is as expected or not
BOOST_TEST((std::is_same<decltype(result.get_x()), quantity<si::length>>::value));
BOOST_TEST((std::is_same<decltype(result.get_y()), quantity<decltype(si::kilo*meter)>>::value));
BOOST_TEST((std::is_same<decltype(result.get_z()), quantity<decltype(si::centi*meter)>>::value));
}

BOOST_AUTO_TEST_SUITE_END()
33 changes: 33 additions & 0 deletions test/coordinate/spherical_equatorial_representation.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -237,6 +237,22 @@ BOOST_AUTO_TEST_CASE(spherical_equatorial_representation_dot_product)
<bu::multiply_typeof_helper<si::length, si::length>::type>>::value));
}

BOOST_AUTO_TEST_CASE(spherical_equatorial_representation_scalar_multiplication)
{
auto point1 = make_spherical_equatorial_representation(25.0 * bud::degrees, 30.0 * bud::degrees, 90.0*meter);

auto result = boost::astronomy::coordinate::multiply(point1, 2);

BOOST_CHECK_CLOSE(result.get_lat().value(), 25.0, 0.001);
BOOST_CHECK_CLOSE(result.get_lon().value(), 30.0, 0.001);
BOOST_CHECK_CLOSE(result.get_dist().value(), 180.0, 0.001);

//checking whether quantity stored is as expected or not
BOOST_TEST((std::is_same<decltype(result.get_lat()), quantity<bud::plane_angle>>::value));
BOOST_TEST((std::is_same<decltype(result.get_lon()), quantity<bud::plane_angle>>::value));
BOOST_TEST((std::is_same<decltype(result.get_dist()), quantity<si::length>>::value));
}

BOOST_AUTO_TEST_CASE(spherical_equatorial_representation_unit_vector)
{
auto point1 = make_spherical_equatorial_representation(25.0 * bud::degrees, 30.0 * bud::degrees, 90.0*meter);
Expand Down Expand Up @@ -283,6 +299,23 @@ BOOST_AUTO_TEST_CASE(spherical_equatorial_representation_sum)
BOOST_TEST((std::is_same<decltype(result.get_dist()), quantity<si::length>>::value));
}

BOOST_AUTO_TEST_CASE(spherical_equatorial_representation_difference)
{
auto point1 = make_spherical_equatorial_representation(15.0 * bud::degrees, 30.0 * bud::degrees, 10.0 * meters);
auto point2 = make_spherical_equatorial_representation(30.0 * bud::degrees, 45.0 * bud::degrees, 20.0 * meters);

auto result = boost::astronomy::coordinate::difference(point2, point1);

BOOST_CHECK_CLOSE(result.get_lat().value(), 51.206, 0.001);
BOOST_CHECK_CLOSE(result.get_lon().value(), 55.8705, 0.001);
BOOST_CHECK_CLOSE(result.get_dist().value(), 11.0443, 0.001);

//checking whether quantity stored is as expected or not
BOOST_TEST((std::is_same<decltype(result.get_lat()), quantity<bud::plane_angle>>::value));
BOOST_TEST((std::is_same<decltype(result.get_lon()), quantity<bud::plane_angle>>::value));
BOOST_TEST((std::is_same<decltype(result.get_dist()), quantity<si::length>>::value));
}

BOOST_AUTO_TEST_CASE(spherical_equatorial_representation_mean)
{
auto point1 = make_spherical_equatorial_representation(15.0 * bud::degrees, 30.0 * bud::degrees, 10.0 * meter);
Expand Down
33 changes: 33 additions & 0 deletions test/coordinate/spherical_representation.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -236,6 +236,22 @@ BOOST_AUTO_TEST_CASE(spherical_representation_dot_product)
<bu::multiply_typeof_helper<si::length, si::length>::type>>::value));
}

BOOST_AUTO_TEST_CASE(spherical_representation_scalar_multiplication)
{
auto point1 = make_spherical_representation(25.0 * bud::degrees, 30.0 * bud::degrees, 90.0*meter);

auto result = boost::astronomy::coordinate::multiply(point1, 2);

BOOST_CHECK_CLOSE(result.get_lat().value(), 25.0, 0.001);
BOOST_CHECK_CLOSE(result.get_lon().value(), 30.0, 0.001);
BOOST_CHECK_CLOSE(result.get_dist().value(), 180.0, 0.001);

//checking whether quantity stored is as expected or not
BOOST_TEST((std::is_same<decltype(result.get_lat()), quantity<bud::plane_angle>>::value));
BOOST_TEST((std::is_same<decltype(result.get_lon()), quantity<bud::plane_angle>>::value));
BOOST_TEST((std::is_same<decltype(result.get_dist()), quantity<si::length>>::value));
}

BOOST_AUTO_TEST_CASE(spherical_representation_unit_vector)
{
auto point1 = make_spherical_representation(25.0 * bud::degrees, 30.0 * bud::degrees, 90.0*meter);
Expand Down Expand Up @@ -282,6 +298,23 @@ BOOST_AUTO_TEST_CASE(spherical_representation_sum)
BOOST_TEST((std::is_same<decltype(result.get_dist()), quantity<si::length>>::value));
}

BOOST_AUTO_TEST_CASE(spherical_representation_difference)
{
auto point1 = make_spherical_representation(15.0 * bud::degrees, 30.0 * bud::degrees, 10.0 * meters);
auto point2 = make_spherical_representation(30.0 * bud::degrees, 45.0 * bud::degrees, 20.0 * meters);

auto result = boost::astronomy::coordinate::difference(point1, point2);

BOOST_CHECK_CLOSE(result.get_lat().value(), -142.089, 0.001);
BOOST_CHECK_CLOSE(result.get_lon().value(), 120.245, 0.001);
BOOST_CHECK_CLOSE(result.get_dist().value(), 10.8834, 0.001);

//checking whether quantity stored is as expected or not
BOOST_TEST((std::is_same<decltype(result.get_lat()), quantity<bud::plane_angle>>::value));
BOOST_TEST((std::is_same<decltype(result.get_lon()), quantity<bud::plane_angle>>::value));
BOOST_TEST((std::is_same<decltype(result.get_dist()), quantity<si::length>>::value));
}

BOOST_AUTO_TEST_CASE(spherical_representation_mean)
{
auto point1 = make_spherical_representation(15.0 * bud::degrees, 30.0 * bud::degrees, 10.0 * meter);
Expand Down