summaryrefslogtreecommitdiff
path: root/modules/codec
diff options
context:
space:
mode:
Diffstat (limited to 'modules/codec')
-rw-r--r--modules/codec/c++/data.hpp27
-rw-r--r--modules/codec/c++/data_math.hpp21
-rw-r--r--modules/codec/c++/math.hpp62
-rw-r--r--modules/codec/tests/math.cpp25
4 files changed, 122 insertions, 13 deletions
diff --git a/modules/codec/c++/data.hpp b/modules/codec/c++/data.hpp
index c43402e..a8b7836 100644
--- a/modules/codec/c++/data.hpp
+++ b/modules/codec/c++/data.hpp
@@ -330,13 +330,28 @@ public:
{
}
- /*
+ /**
+ * Forwarding constructor, so the elements can be written without
+ * spelling out the inner array.
+ *
+ * data<FixedArray<UInt64,3>>{0,1,2} instead of {{0,1,2}}
+ *
+ * The guards keep it out of the way of the copy and the meta schema
+ * constructor in the single element case.
+ *
+ * Explicit for a single element, because a one dimensional index would
+ * otherwise be convertible to both data<UInt64> and this, which makes
+ * the two at overloads of data<Array<T,1>> ambiguous.
+ */
template<typename... Args>
- requires (sizeof...(Args) == ct_multiply<uint64_t, D...>::value) &&
- (std::constructible_from<data<T, encode::Native>, Args> && ...)
- constexpr data(Args&&... args):
- value_{ { std::forward<Args>(args)... } } {}
- */
+ requires (sizeof...(Args) == ct_multiply<uint64_t, D...>::value)
+ && (sizeof...(Args) > 1u
+ || (!std::same_as<std::remove_cvref_t<Args>, data> && ...))
+ && (!std::same_as<std::remove_cvref_t<Args>, data<MetaSchema, encode::Native>> && ...)
+ && (std::constructible_from<data<T, encode::Native>, Args> && ...)
+ explicit(sizeof...(Args) == 1u) constexpr data(Args&&... args):
+ value_{ data<T, encode::Native>{std::forward<Args>(args)}... }
+ {}
SAW_DEFAULT_COPY(data);
SAW_DEFAULT_MOVE(data);
diff --git a/modules/codec/c++/data_math.hpp b/modules/codec/c++/data_math.hpp
index 9d07eb3..7caedd9 100644
--- a/modules/codec/c++/data_math.hpp
+++ b/modules/codec/c++/data_math.hpp
@@ -93,6 +93,27 @@ public:
values_{inner_values__}
{}
+ /**
+ * Forwarding constructor, so a tensor can be written as its elements
+ * in row major order.
+ *
+ * data<Tensor<Float64,2u,2u>>{1.0, 2.0, 3.0, 4.0}
+ * data<Scalar<Float32>>{5.1f}
+ *
+ * The guards keep it out of the way of the copy constructor and of the
+ * two constructors above in the single element case.
+ */
+ template<typename... Args>
+ requires (sizeof...(Args) == ct_multiply<uint64_t, Dims...>::value)
+ && (sizeof...(Args) > 1u
+ || (!std::same_as<std::remove_cvref_t<Args>, data> && ...))
+ && (!std::same_as<std::remove_cvref_t<Args>, data<Inner, encode::Native>> && ...)
+ && (!std::same_as<std::remove_cvref_t<Args>, data<schema::FixedArray<Inner, Dims...>, encode::Native>> && ...)
+ && (std::constructible_from<data<Inner, encode::Native>, Args> && ...)
+ data(Args&&... args):
+ values_{std::forward<Args>(args)...}
+ {}
+
data<Inner, encode::Native>& at(const data<schema::FixedArray<schema::UInt64, sizeof...(Dims)>, encode::Native>& index){
return values_.at(index);
}
diff --git a/modules/codec/c++/math.hpp b/modules/codec/c++/math.hpp
index 1d627e6..f831256 100644
--- a/modules/codec/c++/math.hpp
+++ b/modules/codec/c++/math.hpp
@@ -36,12 +36,30 @@ public:
};
namespace math {
-/*
+/**
+ * Builds a scalar from its native value. Shorthand for the two step
+ * data<T>{value} -> data<Scalar<T>>{...} conversion, which the language won't
+ * do implicitly.
+ */
template<typename T, typename Encoding = FORSTIO_DEFAULT_DATA_ENCODING>
-data<typename T::InnerType,Encoding> norm_2(const data<T,Encoding>& d){
- return {};
+constexpr data<schema::Scalar<T>, Encoding> make_scalar(typename native_data_type<T>::type value){
+ return data<schema::Scalar<T>, Encoding>{data<T,Encoding>{value}};
+}
+
+/**
+ * Builds a vector from its native component values. The dimension is deduced
+ * from the argument count.
+ */
+template<typename T, typename Encoding = FORSTIO_DEFAULT_DATA_ENCODING, typename... Args>
+constexpr data<schema::Vector<T,sizeof...(Args)>, Encoding> make_vector(Args... args){
+ return data<schema::Vector<T,sizeof...(Args)>, Encoding>{
+ data<schema::FixedArray<T,sizeof...(Args)>, Encoding>{
+ std::array<data<T,Encoding>, sizeof...(Args)>{
+ data<T,Encoding>{static_cast<typename native_data_type<T>::type>(args)}...
+ }
+ }
+ };
}
-*/
template<typename T, uint64_t D, typename Encoding = FORSTIO_DEFAULT_DATA_ENCODING>
data<schema::Scalar<T>, Encoding> dot(const data<schema::Vector<T,D>, Encoding>& left, const data<schema::Vector<T,D>, Encoding>& right){
@@ -61,6 +79,14 @@ data<schema::Scalar<T>,Encoding> sqrt(const data<schema::Scalar<T>,Encoding>& in
return out;
}
+/**
+ * Euclidean length of a vector.
+ */
+template<typename T, uint64_t D, typename Encoding = FORSTIO_DEFAULT_DATA_ENCODING>
+data<schema::Scalar<T>, Encoding> norm(const data<schema::Vector<T,D>, Encoding>& input){
+ return sqrt<T,Encoding>(dot<T,D,Encoding>(input,input));
+}
+
template<typename T, uint64_t D, typename Encoding = FORSTIO_DEFAULT_DATA_ENCODING>
data<schema::Vector<T,D>, Encoding> normalize(const data<schema::Vector<T,D>>& input ) {
auto inp_dot = dot<T,D,Encoding>(input,input);
@@ -174,6 +200,32 @@ data<schema::Scalar<T>,Encoding> sin(
}
+/**
+ * Angle of a 2d vector measured counter clockwise from the positive x axis.
+ * Inverse of unit_vector().
+ */
+template<typename T, typename Encoding = FORSTIO_DEFAULT_DATA_ENCODING>
+data<schema::Scalar<T>,Encoding> angle(
+ const data<schema::Vector<T,2u>, Encoding>& vec
+){
+ data<schema::Scalar<T>,Encoding> ret;
+ ret.at({}).set(std::atan2(vec.at({{1u}}).get(), vec.at({{0u}}).get()));
+ return ret;
+}
+
+/**
+ * Unit length 2d vector pointing along the given angle. Inverse of angle().
+ */
+template<typename T, typename Encoding = FORSTIO_DEFAULT_DATA_ENCODING>
+data<schema::Vector<T,2u>,Encoding> unit_vector(
+ const data<schema::Scalar<T>, Encoding>& rot
+){
+ data<schema::Vector<T,2u>,Encoding> ret;
+ ret.at({{0u}}) = cos<T,Encoding>(rot).at({});
+ ret.at({{1u}}) = sin<T,Encoding>(rot).at({});
+ return ret;
+}
+
template<typename T, typename Encoding = FORSTIO_DEFAULT_DATA_ENCODING>
data<schema::Vector<T,2u>,Encoding> rotate(
const data<schema::Vector<T,2u>, Encoding> vec,
@@ -192,7 +244,7 @@ data<schema::Vector<T,D>,Encoding> scale(
){
data<schema::Vector<T,D>, Encoding> sc_vec;
for(uint64_t i = 0u; i< D; ++i){
- sc_vec.at({{i}}) = vec.at({{i}}) * scale;
+ sc_vec.at({{i}}) = vec.at({{i}}) * scale.at({});
}
return sc_vec;
}
diff --git a/modules/codec/tests/math.cpp b/modules/codec/tests/math.cpp
index 18b6c41..ad79c95 100644
--- a/modules/codec/tests/math.cpp
+++ b/modules/codec/tests/math.cpp
@@ -24,8 +24,29 @@ SAW_TEST("Math/Basic"){
SAW_TEST("Math/Tensor Construction"){
using namespace saw;
- // data<sch::Scalar<sch::Float32>> a{{5.1f}};
- // data<sch::Vector<sch::Int32,3u>> b{{{1,3,5}}};
+ data<sch::Vector<sch::Int32,3u>> b{1,3,5};
+
+ /**
+ * A one dimensional index keeps the inner braces, since a single
+ * element has to stay explicit to not clash with data<UInt64>.
+ */
+ SAW_EXPECT(b.at({{0u}}).get() == 1, "Wrong value at 0");
+ SAW_EXPECT(b.at({{1u}}).get() == 3, "Wrong value at 1");
+ SAW_EXPECT(b.at({{2u}}).get() == 5, "Wrong value at 2");
+
+ /**
+ * From two dimensions up the index forwards, since it is a FixedArray
+ * itself.
+ *
+ * The elements are given in flat order, and get_flat_index runs the
+ * stride from dimension zero up, so the first index varies fastest.
+ */
+ data<sch::Matrix<sch::Float64,2u,2u>> c{1.0, 2.0, 3.0, 4.0};
+
+ SAW_EXPECT(c.at({0u,0u}).get() == 1.0, "Wrong value at 0,0");
+ SAW_EXPECT(c.at({1u,0u}).get() == 2.0, "Wrong value at 1,0");
+ SAW_EXPECT(c.at({0u,1u}).get() == 3.0, "Wrong value at 0,1");
+ SAW_EXPECT(c.at({1u,1u}).get() == 4.0, "Wrong value at 1,1");
}
SAW_TEST("Math/Tensor Fill"){