Skip to content

Commit

Permalink
Merge pull request #29 from open-space-collective/users/robin/access-…
Browse files Browse the repository at this point in the history
…azimuth-elevation-mask

Add Azimuth-Elevation mask
  • Loading branch information
lucas-bremond authored Aug 17, 2020
2 parents 44bbc65 + c2cb6aa commit 20c1929
Show file tree
Hide file tree
Showing 18 changed files with 19,004 additions and 95 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@

#include <OpenSpaceToolkit/Astrodynamics/Access/Generator.hpp>

#include <OpenSpaceToolkitAstrodynamicsPy/Utilities/MapConverter.hpp>

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

inline void OpenSpaceToolkitAstrodynamicsPy_Access_Generator ( )
Expand All @@ -17,6 +19,8 @@ inline void OpenSpaceToolkitAstrodynamicsPy_Access_Generator
using namespace boost::python ;

using ostk::core::types::Shared ;
using ostk::core::types::Real ;
using ostk::core::ctnr::Map ;

using ostk::physics::Environment ;
using ostk::physics::coord::spherical::AER ;
Expand Down Expand Up @@ -60,6 +64,14 @@ inline void OpenSpaceToolkitAstrodynamicsPy_Access_Generator

.def("undefined", &Generator::Undefined).staticmethod("undefined")
.def("aer_ranges", &Generator::AerRanges).staticmethod("aer_ranges")
.def("aer_mask", &Generator::AerMask).staticmethod("aer_mask")

;

MapConverter()

.from_python<Map<Real, Real>>()
.to_python<Map<Real, Real>>()

;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ struct ToListConverter
struct IterableConverter
{

/// @brief Registers converter from a python interable type to the provided type
/// @brief Registers converter from a python iterable type to the provided type

template <typename Container>
IterableConverter& from_python ( )
Expand All @@ -54,7 +54,7 @@ struct IterableConverter

}

/// @brief Registers converter from the provided type to a python interable type
/// @brief Registers converter from the provided type to a python iterable type

template <typename Container>
IterableConverter& to_python ( )
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,155 @@
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

/// @project Open Space Toolkit ▸ Astrodynamics
/// @file bindings/python/src/OpenSpaceToolkitAstrodynamicsPy/Utilities/MapConverter.hpp
/// @author Robin Petitdemange <robin@loftorbital.com>
/// @license Apache License 2.0

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

#ifndef __OpenSpaceToolkitAstrodynamicsPy_Utilities_MapConverter__
#define __OpenSpaceToolkitAstrodynamicsPy_Utilities_MapConverter__

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

// https://stackoverflow.com/questions/42952781/how-to-wrap-a-c-class-with-a-constructor-that-takes-a-stdmap-or-stdvector
// https://stackoverflow.com/questions/6116345/boostpython-possible-to-automatically-convert-from-dict-stdmap
// https://stackoverflow.com/questions/15842126/feeding-a-python-list-into-a-function-taking-in-a-vector-with-boost-python
// https://misspent.wordpress.com/2009/09/27/how-to-write-boost-python-converters/
// https://www.boost.org/doc/libs/1_39_0/libs/python/doc/v2/faq.html#custom_string

template <typename Container>
struct ToDictConverter
{

static PyObject* convert ( const Container& aContainer )
{

boost::python::dict dict ;

for (const auto& element : aContainer)
{
dict[element.first] = element.second ;
}

return boost::python::incref(dict.ptr()) ;

}

} ;

struct MapConverter
{

/// @brief Registers converter from a python iterable type to the provided type

template <typename Container>
MapConverter& from_python ( )
{

boost::python::converter::registry::push_back
(
&MapConverter::convertible,
&MapConverter::construct<Container>,
boost::python::type_id<Container>()
) ;

return *this ;

}

/// @brief Registers converter from the provided type to a python iterable type

template <typename Container>
MapConverter& to_python ( )
{

boost::python::to_python_converter<Container, ToDictConverter<Container>>() ;

return *this ;

}

/// @brief Check if PyObject is iterable

static void* convertible ( PyObject* anObject )
{
return PyObject_GetIter(anObject) ? anObject : nullptr ;
}

/// @brief Convert iterable PyObject to C++ container type.
///
/// Container Concept requirements:
///
/// * Container to be constructed is a map.

template <typename Container>
static void construct ( PyObject* object,
boost::python::converter::rvalue_from_python_stage1_data* data )
{

namespace python = boost::python ;

// Object is a borrowed reference, so create a handle indicting it is borrowed for proper reference counting

python::handle<> handle(python::borrowed(object)) ;

// Obtain a handle to the memory block that the converter has allocated for the C++ type

typedef python::converter::rvalue_from_python_storage<Container> storage_type ;

void* storage = reinterpret_cast<storage_type*>(data)->storage.bytes ;

// Allocate the C++ type into the converter's memory block

new (storage) Container() ;

// Iterate over the dictionary and populate the map

python::dict dict(handle) ;

Container& map(*(static_cast<Container*>(storage))) ;

python::list keys(dict.keys()) ;
int keyCount(static_cast<int>(python::len(keys))) ;

for (int i = 0 ; i < keyCount ; ++i)
{

python::object keyObj(keys[i]) ;
python::extract<typename Container::key_type> keyProxy(keyObj) ;

if (!keyProxy.check())
{
PyErr_SetString(PyExc_KeyError, "Bad key type.") ;
python::throw_error_already_set() ;
}

typename Container::key_type key = keyProxy() ;

python::object valObj(dict[keyObj]) ;
python::extract<typename Container::mapped_type> valProxy(valObj) ;

if (!valProxy.check())
{
PyErr_SetString(PyExc_ValueError, "Bad value type.") ;
python::throw_error_already_set() ;
}

typename Container::mapped_type val = valProxy() ;

map.insert({ key, val }) ;

}

data->convertible = storage ;

}

} ;

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

#endif

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
13 changes: 13 additions & 0 deletions include/OpenSpaceToolkit/Astrodynamics/Access/Generator.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
#include <OpenSpaceToolkit/Mathematics/Objects/Interval.hpp>

#include <OpenSpaceToolkit/Core/Containers/Array.hpp>
#include <OpenSpaceToolkit/Core/Containers/Map.hpp>
#include <OpenSpaceToolkit/Core/Types/Real.hpp>

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
Expand All @@ -38,6 +39,7 @@ namespace access

using ostk::core::types::Real ;
using ostk::core::ctnr::Array ;
using ostk::core::ctnr::Map ;

using ostk::math::obj::Interval ;

Expand Down Expand Up @@ -92,6 +94,17 @@ class Generator
const Interval<Real>& aRangeRange,
const Environment& anEnvironment ) ;

/// @brief Constructs an access generator with a defined AER mask
///
/// @param [in] anAzimuthElevationMask An azimuth-elevation mask [deg]
/// @param [in] aRangeRange A range interval [m]
/// @param [in] anEnvironment An environment
/// @return An access generator

static Generator AerMask ( const Map<Real, Real>& anAzimuthElevationMask,
const Interval<Real>& aRangeRange,
const Environment& anEnvironment ) ;

private:

Environment environment_ ;
Expand Down
64 changes: 64 additions & 0 deletions src/OpenSpaceToolkit/Astrodynamics/Access/Generator.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -538,6 +538,70 @@ Generator Generator::AerRanges (

}

Generator Generator::AerMask ( const Map<Real, Real>& anAzimuthElevationMask,
const Interval<Real>& aRangeRange,
const Environment& anEnvironment )
{

using ostk::core::types::Real ;
using ostk::core::ctnr::Map ;

using ostk::math::obj::Vector2d ;

if ((anAzimuthElevationMask.empty()) || (anAzimuthElevationMask.begin()->first < 0.0) || (anAzimuthElevationMask.rbegin()->first > 360.0))
{
throw ostk::core::error::runtime::Wrong("Azimuth-Elevation Mask") ;
}

for (const auto& azimuthElevationPair : anAzimuthElevationMask)
{
if ((azimuthElevationPair.second).abs() > 90.0)
{
throw ostk::core::error::runtime::Wrong("Azimuth-Elevation Mask") ;
}
}

Map<Real, Real> anAzimuthElevationMask_deg = anAzimuthElevationMask ;
const Interval<Real> rangeRange_m = aRangeRange ;

if (anAzimuthElevationMask_deg.begin()->first != 0.0)
{
anAzimuthElevationMask_deg.insert({ 0.0, anAzimuthElevationMask_deg.begin()->second }) ;
}

if (anAzimuthElevationMask_deg.rbegin()->first != 360.0)
{
anAzimuthElevationMask_deg.insert({ 360.0, anAzimuthElevationMask_deg.begin()->second }) ;
}

const std::function<bool (const AER&)> aerFilter = [anAzimuthElevationMask_deg, rangeRange_m] (const AER& anAER) -> bool
{

const Real azimuth = anAER.getAzimuth().inDegrees(0.0, +360.0) ;
const Real elevation = anAER.getElevation().inDegrees(-180.0, +180.0) ;

auto itLow = anAzimuthElevationMask_deg.lower_bound(azimuth) ; itLow-- ;
auto itUp = anAzimuthElevationMask_deg.upper_bound(azimuth) ;

// Vector between the two successive mask data points with bounding azimuth values

const Vector2d lowToUpVector = { itUp->first - itLow->first, itUp->second - itLow->second } ;

// Vector from data point with azimuth lower bound to tested point

const Vector2d lowToPointVector = { azimuth - itLow->first, elevation - itLow->second } ;

// If the determinant of these two vectors is positive, the tested point lies above the function defined by the mask

return (lowToUpVector[0] * lowToPointVector[1] - lowToUpVector[1] * lowToPointVector[0] >= 0.0)
&& ((!rangeRange_m.isDefined()) || rangeRange_m.contains(anAER.getRange().inMeters())) ;

} ;

return { anEnvironment, aerFilter, {} } ;

}

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

}
Expand Down
Loading

0 comments on commit 20c1929

Please sign in to comment.