From 7e8cbb4d55c6a6858679b0df7320cbbf4320bee0 Mon Sep 17 00:00:00 2001 From: John Wellbelove Date: Tue, 27 Apr 2021 18:30:42 +0100 Subject: [PATCH 01/18] Added percentile & histogram_percentile --- include/etl/percentile.h | 90 +++++++++++++ test/test_percentile.cpp | 222 ++++++++++++++++++++++++++++++++ test/vs2019/etl.vcxproj | 2 + test/vs2019/etl.vcxproj.filters | 6 + 4 files changed, 320 insertions(+) create mode 100644 include/etl/percentile.h create mode 100644 test/test_percentile.cpp diff --git a/include/etl/percentile.h b/include/etl/percentile.h new file mode 100644 index 00000000..13cc0a2b --- /dev/null +++ b/include/etl/percentile.h @@ -0,0 +1,90 @@ +///\file + +/****************************************************************************** +The MIT License(MIT) + +Embedded Template Library. +https://github.com/ETLCPP/etl +https://www.etlcpp.com + +Copyright(c) 2021 jwellbelove + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files(the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and / or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions : + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. +******************************************************************************/ + +#ifndef ETL_PERCENTILE_INCLUDED +#define ETL_PERCENTILE_INCLUDED + +#include "platform.h" +#include "iterator.h" +#include "histogram.h" +#include "algorithm.h" + +namespace etl +{ + //*************************************************************************** + /// Get the iterator to the histogram element at the specified percentile. + /// Uses the nearest-rank method. + //*************************************************************************** + template + TIterator percentile(TIterator first, TIterator last, TPercentile percentile) + { + typedef typename etl::iterator_traits::difference_type difference_type; + + size_t length = size_t(etl::distance(first, last)); + size_t index = size_t(((length * percentile) + TPercentile(99)) / TPercentile(100)); + + if (index != 0) + { + --index; + } + + // Return the iterator to the value at the percentile. + etl::advance(first, index); + return first; + } + + //*************************************************************************** + /// Get the iterator to the histogram element where the sum of the histogram + /// values are at least the specified percentage of the total. + //*************************************************************************** + template + typename TIterator histogram_percentile(TIterator first, TIterator last, TPercentile percentile) + { + uint32_t total = etl::accumulate(first, last, uint32_t(0U)); + uint32_t sum = 0U; + + while (first != last) + { + sum += *first; + + // Return when we have reached or exceeded the required percentile. + if (((TPercentile(100) * sum) / total) >= percentile) + { + return first; + } + + ++first; + } + + return first; + } +} + +#endif \ No newline at end of file diff --git a/test/test_percentile.cpp b/test/test_percentile.cpp new file mode 100644 index 00000000..d15d2ff1 --- /dev/null +++ b/test/test_percentile.cpp @@ -0,0 +1,222 @@ +/****************************************************************************** +The MIT License(MIT) + +Embedded Template Library. +https://github.com/ETLCPP/etl +https://www.etlcpp.com + +Copyright(c) 2021 jwellbelove + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files(the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and / or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions : + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. +******************************************************************************/ + +#include "unit_test_framework.h" + +#include "etl/algorithm.h" +#include "etl/histogram.h" +#include "etl/percentile.h" + +#include + +namespace +{ + constexpr size_t Size = 10U; + + etl::histogram histogram; + + std::array input1a = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 }; + std::array input1b = { 15, 20, 35, 40, 50 }; + std::array input1c = { 3, 6, 7, 8, 8, 10, 13, 15, 16, 20 }; + std::array input1d = { 3, 6, 7, 8, 8, 9, 10, 13, 15, 16, 20 }; + + //*********************************** + std::array input2 = + { + 5, 5, 5, 5, 5, 5, + 4, 4, 4, 4, 4, + 6, 6, 6, 6, 6, 6, 6, + 3, 3, 3, 3, + 7, 7, 7, 7, 7, 7, 7, 7, + 2, 2, 2, + 8, 8, 8, 8, 8, 8, 8, 8, 8, + 1, 1, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 0 + }; + + SUITE(test_percentile) + { + //************************************************************************* + TEST(test_array_percentile) + { + CHECK_EQUAL(0, *etl::percentile(input1a.begin(), input1a.end(), 0U)); + CHECK_EQUAL(0, *etl::percentile(input1a.begin(), input1a.end(), 1U)); + CHECK_EQUAL(0, *etl::percentile(input1a.begin(), input1a.end(), 2U)); + CHECK_EQUAL(0, *etl::percentile(input1a.begin(), input1a.end(), 3U)); + CHECK_EQUAL(0, *etl::percentile(input1a.begin(), input1a.end(), 4U)); + CHECK_EQUAL(0, *etl::percentile(input1a.begin(), input1a.end(), 5U)); + CHECK_EQUAL(0, *etl::percentile(input1a.begin(), input1a.end(), 6U)); + CHECK_EQUAL(0, *etl::percentile(input1a.begin(), input1a.end(), 7U)); + CHECK_EQUAL(0, *etl::percentile(input1a.begin(), input1a.end(), 8U)); + CHECK_EQUAL(0, *etl::percentile(input1a.begin(), input1a.end(), 9U)); + + CHECK_EQUAL(0, *etl::percentile(input1a.begin(), input1a.end(), 10U)); + CHECK_EQUAL(1, *etl::percentile(input1a.begin(), input1a.end(), 11U)); + CHECK_EQUAL(1, *etl::percentile(input1a.begin(), input1a.end(), 12U)); + CHECK_EQUAL(1, *etl::percentile(input1a.begin(), input1a.end(), 13U)); + CHECK_EQUAL(1, *etl::percentile(input1a.begin(), input1a.end(), 14U)); + CHECK_EQUAL(1, *etl::percentile(input1a.begin(), input1a.end(), 15U)); + CHECK_EQUAL(1, *etl::percentile(input1a.begin(), input1a.end(), 16U)); + CHECK_EQUAL(1, *etl::percentile(input1a.begin(), input1a.end(), 17U)); + CHECK_EQUAL(1, *etl::percentile(input1a.begin(), input1a.end(), 18U)); + CHECK_EQUAL(1, *etl::percentile(input1a.begin(), input1a.end(), 19U)); + + CHECK_EQUAL(1, *etl::percentile(input1a.begin(), input1a.end(), 20U)); + CHECK_EQUAL(2, *etl::percentile(input1a.begin(), input1a.end(), 21U)); + CHECK_EQUAL(2, *etl::percentile(input1a.begin(), input1a.end(), 22U)); + CHECK_EQUAL(2, *etl::percentile(input1a.begin(), input1a.end(), 23U)); + CHECK_EQUAL(2, *etl::percentile(input1a.begin(), input1a.end(), 24U)); + CHECK_EQUAL(2, *etl::percentile(input1a.begin(), input1a.end(), 25U)); + CHECK_EQUAL(2, *etl::percentile(input1a.begin(), input1a.end(), 26U)); + CHECK_EQUAL(2, *etl::percentile(input1a.begin(), input1a.end(), 27U)); + CHECK_EQUAL(2, *etl::percentile(input1a.begin(), input1a.end(), 28U)); + CHECK_EQUAL(2, *etl::percentile(input1a.begin(), input1a.end(), 29U)); + + CHECK_EQUAL(2, *etl::percentile(input1a.begin(), input1a.end(), 30U)); + CHECK_EQUAL(3, *etl::percentile(input1a.begin(), input1a.end(), 31U)); + CHECK_EQUAL(3, *etl::percentile(input1a.begin(), input1a.end(), 32U)); + CHECK_EQUAL(3, *etl::percentile(input1a.begin(), input1a.end(), 33U)); + CHECK_EQUAL(3, *etl::percentile(input1a.begin(), input1a.end(), 34U)); + CHECK_EQUAL(3, *etl::percentile(input1a.begin(), input1a.end(), 35U)); + CHECK_EQUAL(3, *etl::percentile(input1a.begin(), input1a.end(), 36U)); + CHECK_EQUAL(3, *etl::percentile(input1a.begin(), input1a.end(), 37U)); + CHECK_EQUAL(3, *etl::percentile(input1a.begin(), input1a.end(), 38U)); + CHECK_EQUAL(3, *etl::percentile(input1a.begin(), input1a.end(), 39U)); + + CHECK_EQUAL(3, *etl::percentile(input1a.begin(), input1a.end(), 40U)); + CHECK_EQUAL(4, *etl::percentile(input1a.begin(), input1a.end(), 41U)); + CHECK_EQUAL(4, *etl::percentile(input1a.begin(), input1a.end(), 42U)); + CHECK_EQUAL(4, *etl::percentile(input1a.begin(), input1a.end(), 43U)); + CHECK_EQUAL(4, *etl::percentile(input1a.begin(), input1a.end(), 44U)); + CHECK_EQUAL(4, *etl::percentile(input1a.begin(), input1a.end(), 45U)); + CHECK_EQUAL(4, *etl::percentile(input1a.begin(), input1a.end(), 46U)); + CHECK_EQUAL(4, *etl::percentile(input1a.begin(), input1a.end(), 47U)); + CHECK_EQUAL(4, *etl::percentile(input1a.begin(), input1a.end(), 48U)); + CHECK_EQUAL(4, *etl::percentile(input1a.begin(), input1a.end(), 49U)); + + CHECK_EQUAL(4, *etl::percentile(input1a.begin(), input1a.end(), 50U)); + CHECK_EQUAL(5, *etl::percentile(input1a.begin(), input1a.end(), 51U)); + CHECK_EQUAL(5, *etl::percentile(input1a.begin(), input1a.end(), 52U)); + CHECK_EQUAL(5, *etl::percentile(input1a.begin(), input1a.end(), 53U)); + CHECK_EQUAL(5, *etl::percentile(input1a.begin(), input1a.end(), 54U)); + CHECK_EQUAL(5, *etl::percentile(input1a.begin(), input1a.end(), 55U)); + CHECK_EQUAL(5, *etl::percentile(input1a.begin(), input1a.end(), 56U)); + CHECK_EQUAL(5, *etl::percentile(input1a.begin(), input1a.end(), 57U)); + CHECK_EQUAL(5, *etl::percentile(input1a.begin(), input1a.end(), 58U)); + CHECK_EQUAL(5, *etl::percentile(input1a.begin(), input1a.end(), 59U)); + + CHECK_EQUAL(5, *etl::percentile(input1a.begin(), input1a.end(), 60U)); + CHECK_EQUAL(6, *etl::percentile(input1a.begin(), input1a.end(), 61U)); + CHECK_EQUAL(6, *etl::percentile(input1a.begin(), input1a.end(), 62U)); + CHECK_EQUAL(6, *etl::percentile(input1a.begin(), input1a.end(), 63U)); + CHECK_EQUAL(6, *etl::percentile(input1a.begin(), input1a.end(), 64U)); + CHECK_EQUAL(6, *etl::percentile(input1a.begin(), input1a.end(), 65U)); + CHECK_EQUAL(6, *etl::percentile(input1a.begin(), input1a.end(), 66U)); + CHECK_EQUAL(6, *etl::percentile(input1a.begin(), input1a.end(), 67U)); + CHECK_EQUAL(6, *etl::percentile(input1a.begin(), input1a.end(), 68U)); + CHECK_EQUAL(6, *etl::percentile(input1a.begin(), input1a.end(), 69U)); + + CHECK_EQUAL(6, *etl::percentile(input1a.begin(), input1a.end(), 70U)); + CHECK_EQUAL(7, *etl::percentile(input1a.begin(), input1a.end(), 71U)); + CHECK_EQUAL(7, *etl::percentile(input1a.begin(), input1a.end(), 72U)); + CHECK_EQUAL(7, *etl::percentile(input1a.begin(), input1a.end(), 73U)); + CHECK_EQUAL(7, *etl::percentile(input1a.begin(), input1a.end(), 74U)); + CHECK_EQUAL(7, *etl::percentile(input1a.begin(), input1a.end(), 75U)); + CHECK_EQUAL(7, *etl::percentile(input1a.begin(), input1a.end(), 76U)); + CHECK_EQUAL(7, *etl::percentile(input1a.begin(), input1a.end(), 77U)); + CHECK_EQUAL(7, *etl::percentile(input1a.begin(), input1a.end(), 78U)); + CHECK_EQUAL(7, *etl::percentile(input1a.begin(), input1a.end(), 79U)); + + CHECK_EQUAL(7, *etl::percentile(input1a.begin(), input1a.end(), 80U)); + CHECK_EQUAL(8, *etl::percentile(input1a.begin(), input1a.end(), 81U)); + CHECK_EQUAL(8, *etl::percentile(input1a.begin(), input1a.end(), 82U)); + CHECK_EQUAL(8, *etl::percentile(input1a.begin(), input1a.end(), 83U)); + CHECK_EQUAL(8, *etl::percentile(input1a.begin(), input1a.end(), 84U)); + CHECK_EQUAL(8, *etl::percentile(input1a.begin(), input1a.end(), 85U)); + CHECK_EQUAL(8, *etl::percentile(input1a.begin(), input1a.end(), 86U)); + CHECK_EQUAL(8, *etl::percentile(input1a.begin(), input1a.end(), 87U)); + CHECK_EQUAL(8, *etl::percentile(input1a.begin(), input1a.end(), 88U)); + CHECK_EQUAL(8, *etl::percentile(input1a.begin(), input1a.end(), 89U)); + + CHECK_EQUAL(8, *etl::percentile(input1a.begin(), input1a.end(), 90U)); + CHECK_EQUAL(9, *etl::percentile(input1a.begin(), input1a.end(), 91U)); + CHECK_EQUAL(9, *etl::percentile(input1a.begin(), input1a.end(), 92U)); + CHECK_EQUAL(9, *etl::percentile(input1a.begin(), input1a.end(), 93U)); + CHECK_EQUAL(9, *etl::percentile(input1a.begin(), input1a.end(), 94U)); + CHECK_EQUAL(9, *etl::percentile(input1a.begin(), input1a.end(), 95U)); + CHECK_EQUAL(9, *etl::percentile(input1a.begin(), input1a.end(), 96U)); + CHECK_EQUAL(9, *etl::percentile(input1a.begin(), input1a.end(), 97U)); + CHECK_EQUAL(9, *etl::percentile(input1a.begin(), input1a.end(), 98U)); + CHECK_EQUAL(9, *etl::percentile(input1a.begin(), input1a.end(), 99U)); + + CHECK_EQUAL(9, *etl::percentile(input1a.begin(), input1a.end(), 100U)); + } + + //************************************************************************* + TEST(test_array_percentile_from_wikipedia_1) + { + CHECK_EQUAL(15, *etl::percentile(input1b.begin(), input1b.end(), 0U)); + CHECK_EQUAL(15, *etl::percentile(input1b.begin(), input1b.end(), 5U)); + CHECK_EQUAL(20, *etl::percentile(input1b.begin(), input1b.end(), 30U)); + CHECK_EQUAL(20, *etl::percentile(input1b.begin(), input1b.end(), 40U)); + CHECK_EQUAL(35, *etl::percentile(input1b.begin(), input1b.end(), 50U)); + CHECK_EQUAL(50, *etl::percentile(input1b.begin(), input1b.end(), 100U)); + } + + //************************************************************************* + TEST(test_array_percentile_from_wikipedia_2) + { + CHECK_EQUAL(7, *etl::percentile(input1c.begin(), input1c.end(), 25U)); + CHECK_EQUAL(8, *etl::percentile(input1c.begin(), input1c.end(), 50U)); + CHECK_EQUAL(15, *etl::percentile(input1c.begin(), input1c.end(), 75U)); + CHECK_EQUAL(20, *etl::percentile(input1c.begin(), input1c.end(), 100U)); + } + + //************************************************************************* + TEST(test_array_percentile_from_wikipedia_3) + { + CHECK_EQUAL(7, *etl::percentile(input1d.begin(), input1d.end(), 25U)); + CHECK_EQUAL(9, *etl::percentile(input1d.begin(), input1d.end(), 50U)); + CHECK_EQUAL(15, *etl::percentile(input1d.begin(), input1d.end(), 75U)); + CHECK_EQUAL(20, *etl::percentile(input1d.begin(), input1d.end(), 100U)); + } + + //************************************************************************* + TEST(test_histogram_percentile) + { + histogram(input2.begin(), input2.end()); + + CHECK_EQUAL(1, *etl::histogram_percentile(histogram.begin(), histogram.end(), 0U)); + CHECK_EQUAL(5, *etl::histogram_percentile(histogram.begin(), histogram.end(), 25U)); + CHECK_EQUAL(7, *etl::histogram_percentile(histogram.begin(), histogram.end(), 50U)); + CHECK_EQUAL(9, *etl::histogram_percentile(histogram.begin(), histogram.end(), 75U)); + CHECK_EQUAL(10, *etl::histogram_percentile(histogram.begin(), histogram.end(), 100U)); + } + }; +} diff --git a/test/vs2019/etl.vcxproj b/test/vs2019/etl.vcxproj index 80c7a26d..a6306d81 100644 --- a/test/vs2019/etl.vcxproj +++ b/test/vs2019/etl.vcxproj @@ -1346,6 +1346,7 @@ + @@ -4869,6 +4870,7 @@ + diff --git a/test/vs2019/etl.vcxproj.filters b/test/vs2019/etl.vcxproj.filters index 8b11f5cf..53249a88 100644 --- a/test/vs2019/etl.vcxproj.filters +++ b/test/vs2019/etl.vcxproj.filters @@ -1101,6 +1101,9 @@ ETL\Frameworks + + ETL\Maths + @@ -2519,6 +2522,9 @@ Source Files + + Source Files + From 76d2ffbd0f0dee8608e36cc83866094d6ea8d15d Mon Sep 17 00:00:00 2001 From: John Wellbelove Date: Thu, 29 Apr 2021 13:17:45 +0100 Subject: [PATCH 02/18] Return 'last' for zero percentile. --- include/etl/percentile.h | 7 ++++++- test/test_percentile.cpp | 2 +- 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/include/etl/percentile.h b/include/etl/percentile.h index 13cc0a2b..64cf5181 100644 --- a/include/etl/percentile.h +++ b/include/etl/percentile.h @@ -65,8 +65,13 @@ namespace etl /// values are at least the specified percentage of the total. //*************************************************************************** template - typename TIterator histogram_percentile(TIterator first, TIterator last, TPercentile percentile) + TIterator histogram_percentile(TIterator first, TIterator last, TPercentile percentile) { + if (percentile == TPercentile(0)) + { + return last; + } + uint32_t total = etl::accumulate(first, last, uint32_t(0U)); uint32_t sum = 0U; diff --git a/test/test_percentile.cpp b/test/test_percentile.cpp index d15d2ff1..c030b85d 100644 --- a/test/test_percentile.cpp +++ b/test/test_percentile.cpp @@ -212,7 +212,7 @@ namespace { histogram(input2.begin(), input2.end()); - CHECK_EQUAL(1, *etl::histogram_percentile(histogram.begin(), histogram.end(), 0U)); + CHECK((etl::histogram_percentile(histogram.begin(), histogram.end(), 0U)) == histogram.end()); CHECK_EQUAL(5, *etl::histogram_percentile(histogram.begin(), histogram.end(), 25U)); CHECK_EQUAL(7, *etl::histogram_percentile(histogram.begin(), histogram.end(), 50U)); CHECK_EQUAL(9, *etl::histogram_percentile(histogram.begin(), histogram.end(), 75U)); From 083a1e39b00e8fcac06a078736894894e4e53191 Mon Sep 17 00:00:00 2001 From: John Wellbelove Date: Fri, 30 Apr 2021 17:17:03 +0100 Subject: [PATCH 03/18] Added etl::for_each_iterator --- include/etl/algorithm.h | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/include/etl/algorithm.h b/include/etl/algorithm.h index 8c759ac4..b951975d 100644 --- a/include/etl/algorithm.h +++ b/include/etl/algorithm.h @@ -3079,6 +3079,28 @@ namespace etl return begin; } + //*************************************************************************** + /// Like std::for_each but passes the iterator to the function. + /// There is currently no STL equivalent. + ///\ingroup algorithm + //*************************************************************************** + template + TUnaryFunction for_each_iterator(TIterator begin, + const TIterator end, + TUnaryFunction function) + { + while (begin != end) + { + function(begin); + + ++begin; + } + + return function; + } + //*************************************************************************** /// A safer form of std::transform where the transform returns when the first /// range end is reached. From ce3dca4ec21983f65545654fdf436eed10cadcaa Mon Sep 17 00:00:00 2001 From: John Wellbelove Date: Fri, 30 Apr 2021 17:17:30 +0100 Subject: [PATCH 04/18] Added TCoordinate default type --- include/etl/bresenham_line.h | 36 ++++++++++++++++++------------------ 1 file changed, 18 insertions(+), 18 deletions(-) diff --git a/include/etl/bresenham_line.h b/include/etl/bresenham_line.h index 412b99d2..1016a7a5 100644 --- a/include/etl/bresenham_line.h +++ b/include/etl/bresenham_line.h @@ -46,8 +46,9 @@ namespace etl /// line algorithm. /// T is the type for the etl::coordinate_2d value type. /// TWork is the internal working variable type. Default is int16_t. + /// TCoordinate is the coordinate type. Default is etl::coordinate_2d //*************************************************************************** - template + template > class bresenham_line { public: @@ -55,13 +56,12 @@ namespace etl //*************************************************** /// Standard container types. //*************************************************** - typedef etl::coordinate_2d value_type; - typedef size_t size_type; - typedef ptrdiff_t difference_type; - typedef value_type& reference; - typedef const value_type& const_reference; - typedef value_type* pointer; - typedef const value_type* const_pointer; + typedef TCoordinate value_type; + typedef size_t size_type; + typedef value_type& reference; + typedef const value_type& const_reference; + typedef value_type* pointer; + typedef const value_type* const_pointer; //*************************************************** /// Const Iterator @@ -159,14 +159,14 @@ namespace etl //*************************************************** bresenham_line() { - initialise(T(0), T(0), T(0), T(0)); + initialise(TWork(0), TWork(0), TWork(0), TWork(0)); } //*************************************************** /// Constructor. /// Supplied first and last coordinates //*************************************************** - bresenham_line(etl::coordinate_2d first_, etl::coordinate_2d last_) + bresenham_line(value_type first_, value_type last_) { initialise(first_.x, first_.y, last_.x, last_.y); } @@ -175,7 +175,7 @@ namespace etl /// Constructor. /// Supplied first and last coordinates //*************************************************** - bresenham_line(T first_x, T first_y, T last_x, T last_y) + bresenham_line(TWork first_x, TWork first_y, TWork last_x, TWork last_y) { initialise(first_x, first_y, last_x, last_y); } @@ -184,7 +184,7 @@ namespace etl /// Resets the line. /// Supplied first and last coordinates //*************************************************** - void reset(etl::coordinate_2d first_, etl::coordinate_2d last_) + void reset(value_type first_, value_type last_) { initialise(first_.x, first_.y, last_.x, last_.y); } @@ -193,7 +193,7 @@ namespace etl /// Resets the line. /// Supplied first and last coordinates //*************************************************** - void reset(T first_x, T first_y, T last_x, T last_y) + void reset(TWork first_x, TWork first_y, TWork last_x, TWork last_y) { initialise(first_x, first_y, last_x, last_y); } @@ -269,7 +269,7 @@ namespace etl //*************************************************** /// Get the current number of generated points. //*************************************************** - void initialise(T first_x, T first_y, T last_x, T last_y) + void initialise(TWork first_x, TWork first_y, TWork last_x, TWork last_y) { first = value_type(first_x, first_y); last = value_type(last_x, last_y); @@ -312,11 +312,11 @@ namespace etl // Y is major axis. if (do_minor_increment) { - coordinate.x = T(coordinate.x + x_increment); + coordinate.x = TWork(coordinate.x + x_increment); balance -= dy; } - coordinate.y = T(coordinate.y + y_increment); + coordinate.y = TWork(coordinate.y + y_increment); balance += dx; } else @@ -324,11 +324,11 @@ namespace etl // X is major axis. if (do_minor_increment) { - coordinate.y = T(coordinate.y + y_increment); + coordinate.y = TWork(coordinate.y + y_increment); balance -= dx; } - coordinate.x = T(coordinate.x + x_increment); + coordinate.x = TWork(coordinate.x + x_increment); balance += dy; } From cefccdd9902a296979f500c0faaa34fa81fe6326 Mon Sep 17 00:00:00 2001 From: John Wellbelove Date: Fri, 30 Apr 2021 17:20:49 +0100 Subject: [PATCH 05/18] Added etl::bresenham_line_iterator --- include/etl/bresenham_line_pointer.h | 381 ++++++++++++++++++ test/test_bresenham_line_pointer.cpp | 569 +++++++++++++++++++++++++++ test/vs2019/etl.vcxproj | 2 + test/vs2019/etl.vcxproj.filters | 6 + 4 files changed, 958 insertions(+) create mode 100644 include/etl/bresenham_line_pointer.h create mode 100644 test/test_bresenham_line_pointer.cpp diff --git a/include/etl/bresenham_line_pointer.h b/include/etl/bresenham_line_pointer.h new file mode 100644 index 00000000..ab68446c --- /dev/null +++ b/include/etl/bresenham_line_pointer.h @@ -0,0 +1,381 @@ +///\file + +/****************************************************************************** +The MIT License(MIT) + +Embedded Template Library. +https://github.com/ETLCPP/etl +https://www.etlcpp.com + +Copyright(c) 2020 jwellbelove + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files(the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and / or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions : + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. +******************************************************************************/ + +#ifndef ETL_BRESENHAM_LINE_POINTER_INCLUDED +#define ETL_BRESENHAM_LINE_POINTER_INCLUDED + +#include + +#include "platform.h" +#include "iterator.h" +#include "static_assert.h" +#include "type_traits.h" +#include "utility.h" + +namespace etl +{ + //*************************************************************************** + /// A pseudo-container that generates pointers to points on a line, using Bresenham's + /// line algorithm. + /// T is the type of the type of the value being pointerd to. + /// TWork is the internal working variable type. Default is int16_t. + //*************************************************************************** + template + class bresenham_line_pointer + { + public: + + //*************************************************** + /// Standard container types. + //*************************************************** + typedef size_t size_type; + typedef T* pointer; + + //*************************************************** + /// Iterator + //*************************************************** + class iterator : public etl::iterator + { + public: + + friend class bresenham_line_pointer; + + //*************************************************** + /// Default constructor + //*************************************************** + iterator() + : p_bresenham_line_pointer(ETL_NULLPTR) + { + } + + //*************************************************** + /// Constuctor + //*************************************************** + iterator(const iterator& other) + : p_bresenham_line_pointer(other.p_bresenham_line_pointer) + { + } + + //*************************************************** + /// Assignment operator + //*************************************************** + iterator& operator =(const iterator& rhs) + { + p_bresenham_line_pointer = rhs.p_bresenham_line_pointer; + + return *this; + } + + //*************************************************** + /// Pre-increment operator + //*************************************************** + iterator& operator ++() + { + // Has the end of the series has been reached? + if (p_bresenham_line_pointer->get_pointer() == p_bresenham_line_pointer->back()) + { + // Mark it as an end iterator. + p_bresenham_line_pointer = ETL_NULLPTR; + } + else + { + p_bresenham_line_pointer->next(); + } + + return *this; + } + + //*************************************************** + /// De-reference operator + //*************************************************** + pointer operator *() + { + return p_bresenham_line_pointer->get_pointer(); + } + + //*************************************************** + /// De-reference operator + //*************************************************** + pointer operator *() const + { + return p_bresenham_line_pointer->get_pointer(); + } + + //*************************************************** + /// Equality operator + //*************************************************** + friend bool operator ==(const iterator& lhs, const iterator& rhs) + { + return lhs.p_bresenham_line_pointer == rhs.p_bresenham_line_pointer; + } + + //*************************************************** + /// Inequality operator + //*************************************************** + friend bool operator !=(const iterator& lhs, const iterator& rhs) + { + return !(lhs == rhs); + } + + private: + + //*************************************************** + /// Constructor for use by bresenham_line_pointer + //*************************************************** + iterator(bresenham_line_pointer* pb) + : p_bresenham_line_pointer(pb) + { + } + + bresenham_line_pointer* p_bresenham_line_pointer; + }; + + //*************************************************** + /// Constructor. + /// Supplied first and last coordinates + //*************************************************** + bresenham_line_pointer(pointer origin_, size_t stride_) + { + initialise(origin_, stride_); + } + + //*************************************************** + /// Constructor. + /// Supplied first and last coordinates + //*************************************************** + bresenham_line_pointer(pointer origin_, size_t stride_, TWork first_x_, TWork first_y_, TWork last_x_, TWork last_y_) + { + initialise(origin_, stride_, first_x_, first_y_, last_x_, last_y_); + } + + //*************************************************** + /// Resets the line. + /// Supplied first and last coordinates + //*************************************************** + void reset(TWork first_x_, TWork first_y_, TWork last_x_, TWork last_y_) + { + initialise(first_x_, first_y_, last_x_, last_y_); + } + + //*************************************************** + /// Get a iterator to the first coordinate. + /// Resets the Bresenham line. + //*************************************************** + iterator begin() + { + pixel = front(); + + return iterator(this); + } + + //*************************************************** + /// Get a iterator to one past the last coordinate. + //*************************************************** + iterator end() const + { + return iterator(); + } + + //*************************************************** + /// Get the first pointer. + //*************************************************** + pointer front() const + { + return origin + first_x + (stride * first_y); + } + + //*************************************************** + /// Get the last pointer. + //*************************************************** + pointer back() const + { + return origin + last_x + (stride * last_y); + } + + //*************************************************** + /// Get the size of the series. + //*************************************************** + size_t size() const + { + if (y_is_major_axis()) + { + return (dy / 2) + 1; + } + else + { + return (dx / 2) + 1; + } + } + + //*************************************************** + /// Equality operator + //*************************************************** + friend bool operator ==(const bresenham_line_pointer& lhs, const bresenham_line_pointer& rhs) + { + return (lhs.front() == rhs.front()) && (lhs.back() == rhs.back()); + } + + //*************************************************** + /// Inequality operator + //*************************************************** + friend bool operator !=(const bresenham_line_pointer& lhs, const bresenham_line_pointer& rhs) + { + return !(lhs == rhs); + } + + private: + + //*************************************************** + /// + //*************************************************** + void initialise(pointer origin_, size_t stride_) + { + origin = origin_; + stride = stride_; + } + + //*************************************************** + /// + //*************************************************** + void initialise(pointer origin_, size_t stride_, TWork first_x_, TWork first_y_, TWork last_x_, TWork last_y_) + { + origin = origin_; + stride = stride_; + + initialise(first_x_, first_y_, last_x_, last_y_); + } + + //*************************************************** + /// + //*************************************************** + void initialise(TWork first_x_, TWork first_y_, TWork last_x_, TWork last_y_) + { + pixel = origin + first_x_ + (stride * first_y_); + first_x = first_x_; + first_y = first_y_; + last_x = last_x_; + last_y = last_y_; + x_increment = (last_x_ < first_x_) ? -1 : 1; + y_increment = (last_y_ < first_y_) ? -work_t(stride) : work_t(stride); + dx = (last_x_ < first_x_) ? first_x_ - last_x_ : last_x_ - first_x_; + dy = (last_y_ < first_y_) ? first_y_ - last_y_ : last_y_ - first_y_; + do_minor_increment = false; + + if (y_is_major_axis()) + { + dx *= 2; + balance = dx - dy; + dy *= 2; + } + else + { + dy *= 2; + balance = dy - dx; + dx *= 2; + } + } + + //*************************************************** + /// Returns true if Y is the major axis. + //*************************************************** + bool y_is_major_axis() const + { + return dx < dy; + } + + //*************************************************** + /// Calculate the next point. + //*************************************************** + void next() + { + if (y_is_major_axis()) + { + // Y is major axis. + if (do_minor_increment) + { + pixel += x_increment; + balance -= dy; + } + + pixel += y_increment; + balance += dx; + } + else + { + // X is major axis. + if (do_minor_increment) + { + pixel += y_increment; + balance -= dx; + } + + pixel += x_increment; + balance += dy; + } + + do_minor_increment = (balance >= 0); + } + + //*************************************************** + /// Get the pointer to the current pixel. + //*************************************************** + pointer get_pointer() + { + return pixel; + } + + //*************************************************** + /// Get the pointer to the current pixel. + //*************************************************** + const pointer get_pointer() const + { + return pixel; + } + + typedef TWork work_t; + + pointer origin; + size_type stride; + work_t first_x; + work_t first_y; + work_t last_x; + work_t last_y; + pointer pixel; + work_t x_increment; + work_t y_increment; + work_t dx; + work_t dy; + work_t balance; + bool do_minor_increment; + }; +} + +#endif + diff --git a/test/test_bresenham_line_pointer.cpp b/test/test_bresenham_line_pointer.cpp new file mode 100644 index 00000000..047fe1a4 --- /dev/null +++ b/test/test_bresenham_line_pointer.cpp @@ -0,0 +1,569 @@ +/****************************************************************************** +The MIT License(MIT) + +Embedded Template Library. +https://github.com/ETLCPP/etl +https://www.etlcpp.com + +Copyright(c) 2020 jwellbelove + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files(the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and / or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions : + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. +******************************************************************************/ + +#include "unit_test_framework.h" + +#include "etl/bresenham_line_pointer.h" + +#include +#include + +namespace etl +{ + //template + //std::ostream& operator << (std::ostream& os, const etl::coordinate_2d& point) + //{ + // os << "(" << int(point.x) << "," << int(point.y) << ")"; + // return os; + //} +} + +namespace +{ + using Value = uint16_t; + + using Point = etl::coordinate_2d; + + std::ostream& operator << (std::ostream& os, const Point& point) + { + os << "(" << int(point.x) << "," << int(point.y) << ")"; + return os; + } + + // The 11 x 11 image + std::array, 10> image = + { + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, + 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, + 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, + 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, + 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, + 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, + 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, + 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, + 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, + 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, + }; + + const std::array, 10> const_image = + { + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, + 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, + 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, + 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, + 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, + 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, + 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, + 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, + 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, + 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, + }; + + // Convert a coordinate to a pointer. + constexpr Value* GetPointer(Value x, Value y) + { + return &image[y][x]; + } + + constexpr const Value* GetConstPointer(Value x, Value y) + { + return &const_image[y][x]; + } + + // Convert a coordinate to an expected value. + constexpr Value GetValue(Value x, Value y) + { + return (x + (y * 10)); + } + + Value* origin = &image[0][0]; + const Value* const_origin = &const_image[0][0]; + constexpr size_t stride = image.size(); + + using BresenhamLinePointer = etl::bresenham_line_pointer; + using BresenhamLinePointerConst = etl::bresenham_line_pointer; + + SUITE(test_bresenham_line_pointer) + { + //************************************************************************* + TEST(horizontal_line_left_right) + { + Point first = { 0, 5 }; + Point last = { 9, 5 }; + + Value* first_ptr = GetPointer(first.x, first.y); + Value* last_ptr = GetPointer(last.x, last.y); + + BresenhamLinePointer bl(origin, stride, first.x, first.y, last.x, last.y); + + CHECK_EQUAL(first_ptr, bl.front()); + CHECK_EQUAL(last_ptr, bl.back()); + + std::vector expected { GetPointer(0, 5), GetPointer(1, 5), GetPointer(2, 5), GetPointer(3, 5), GetPointer(4, 5), + GetPointer(5, 5), GetPointer(6, 5), GetPointer(7, 5), GetPointer(8, 5), GetPointer(9, 5) }; + + std::vector actual; + + for (BresenhamLinePointer::iterator itr = bl.begin(); itr != bl.end(); ++itr) + { + actual.push_back(*itr); + } + + CHECK_EQUAL(expected.size(), bl.size()); + CHECK_EQUAL(expected.size(), actual.size()); + CHECK_ARRAY_EQUAL(expected.data(), actual.data(), (std::max(expected.size(), actual.size()))); + } + + //************************************************************************* + TEST(horizontal_line_left_right_const) + { + Point first = { 0, 5 }; + Point last = { 9, 5 }; + + const Value* first_ptr = GetConstPointer(first.x, first.y); + const Value* last_ptr = GetConstPointer(last.x, last.y); + + BresenhamLinePointerConst bl(const_origin, stride, first.x, first.y, last.x, last.y); + + CHECK_EQUAL(first_ptr, bl.front()); + CHECK_EQUAL(last_ptr, bl.back()); + + std::vector expected { GetConstPointer(0, 5), GetConstPointer(1, 5), GetConstPointer(2, 5), GetConstPointer(3, 5), GetConstPointer(4, 5), + GetConstPointer(5, 5), GetConstPointer(6, 5), GetConstPointer(7, 5), GetConstPointer(8, 5), GetConstPointer(9, 5) }; + + std::vector actual; + + for (BresenhamLinePointerConst::iterator itr = bl.begin(); itr != bl.end(); ++itr) + { + actual.push_back(*itr); + } + + CHECK_EQUAL(expected.size(), bl.size()); + CHECK_EQUAL(expected.size(), actual.size()); + CHECK_ARRAY_EQUAL(expected.data(), actual.data(), (std::max(expected.size(), actual.size()))); + } + + //************************************************************************* + TEST(horizontal_line_right_left) + { + Point first = { 9, 5 }; + Point last = { 0, 5 }; + + Value* first_ptr = GetPointer(first.x, first.y); + Value* last_ptr = GetPointer(last.x, last.y); + + BresenhamLinePointer bl(origin, stride, first.x, first.y, last.x, last.y); + + CHECK_EQUAL(first_ptr, bl.front()); + CHECK_EQUAL(last_ptr, bl.back()); + + std::vector expected { GetPointer(9, 5), GetPointer(8, 5), GetPointer(7, 5), GetPointer(6, 5), GetPointer(5, 5), + GetPointer(4, 5), GetPointer(3, 5), GetPointer(2, 5), GetPointer(1, 5), GetPointer(0, 5) }; + + std::vector actual; + + for (BresenhamLinePointer::iterator itr = bl.begin(); itr != bl.end(); ++itr) + { + actual.push_back(*itr); + } + + CHECK_EQUAL(expected.size(), bl.size()); + CHECK_EQUAL(expected.size(), actual.size()); + CHECK_ARRAY_EQUAL(expected.data(), actual.data(), (std::max(expected.size(), actual.size()))); + } + + //************************************************************************* + TEST(vertical_line_bottom_top) + { + Point first = { 5, 0 }; + Point last = { 5, 9 }; + + Value* first_ptr = GetPointer(first.x, first.y); + Value* last_ptr = GetPointer(last.x, last.y); + + BresenhamLinePointer bl(origin, stride, first.x, first.y, last.x, last.y); + + CHECK_EQUAL(first_ptr, bl.front()); + CHECK_EQUAL(last_ptr, bl.back()); + + std::vector expected { GetPointer(5, 0), GetPointer(5, 1), GetPointer(5, 2), GetPointer(5, 3), GetPointer(5, 4), + GetPointer(5, 5), GetPointer(5, 6), GetPointer(5, 7), GetPointer(5, 8), GetPointer(5, 9) }; + + std::vector actual; + + for (BresenhamLinePointer::iterator itr = bl.begin(); itr != bl.end(); ++itr) + { + actual.push_back(*itr); + } + + CHECK_EQUAL(expected.size(), bl.size()); + CHECK_EQUAL(expected.size(), actual.size()); + CHECK_ARRAY_EQUAL(expected.data(), actual.data(), (std::max(expected.size(), actual.size()))); + } + + //************************************************************************* + TEST(vertical_line_top_bottom) + { + Point first = { 5, 9 }; + Point last = { 5, 0 }; + + Value* first_ptr = GetPointer(first.x, first.y); + Value* last_ptr = GetPointer(last.x, last.y); + + BresenhamLinePointer bl(origin, stride, first.x, first.y, last.x, last.y); + + CHECK_EQUAL(first_ptr, bl.front()); + CHECK_EQUAL(last_ptr, bl.back()); + + std::vector expected { GetPointer(5, 9), GetPointer(5, 8), GetPointer(5, 7), GetPointer(5, 6), GetPointer(5, 5), + GetPointer(5, 4), GetPointer(5, 3), GetPointer(5, 2), GetPointer(5, 1), GetPointer(5, 0) }; + + std::vector actual; + + for (BresenhamLinePointer::iterator itr = bl.begin(); itr != bl.end(); ++itr) + { + actual.push_back(*itr); + } + + CHECK_EQUAL(expected.size(), bl.size()); + CHECK_EQUAL(expected.size(), actual.size()); + CHECK_ARRAY_EQUAL(expected.data(), actual.data(), (std::max(expected.size(), actual.size()))); + } + + //************************************************************************* + TEST(low_slope_diagonal_line_bottom_left_top_right) + { + Point first = { 0, 6 }; + Point last = { 9, 2 }; + + Value* first_ptr = GetPointer(first.x, first.y); + Value* last_ptr = GetPointer(last.x, last.y); + + BresenhamLinePointer bl(origin, stride, first.x, first.y, last.x, last.y); + + CHECK_EQUAL(first_ptr, bl.front()); + CHECK_EQUAL(last_ptr, bl.back()); + + std::vector expected { GetPointer(0, 6), GetPointer(1, 6), GetPointer(2, 5), GetPointer(3, 5), GetPointer(4, 4), + GetPointer(5, 4), GetPointer(6, 3), GetPointer(7, 3), GetPointer(8, 2), GetPointer(9, 2) }; + + std::vector actual; + + for (BresenhamLinePointer::iterator itr = bl.begin(); itr != bl.end(); ++itr) + { + actual.push_back(*itr); + } + + CHECK_EQUAL(expected.size(), bl.size()); + CHECK_EQUAL(expected.size(), actual.size()); + CHECK_ARRAY_EQUAL(expected.data(), actual.data(), (std::max(expected.size(), actual.size()))); + } + + //************************************************************************* + TEST(low_slope_diagonal_line_top_right_bottom_left) + { + Point first = { 9, 2 }; + Point last = { 0, 6 }; + + Value* first_ptr = GetPointer(first.x, first.y); + Value* last_ptr = GetPointer(last.x, last.y); + + BresenhamLinePointer bl(origin, stride, first.x, first.y, last.x, last.y); + + CHECK_EQUAL(first_ptr, bl.front()); + CHECK_EQUAL(last_ptr, bl.back()); + + std::vector expected { GetPointer(9, 2), GetPointer(8, 2), GetPointer(7, 3), GetPointer(6, 3), GetPointer(5, 4), + GetPointer(4, 4), GetPointer(3, 5), GetPointer(2, 5), GetPointer(1, 6), GetPointer(0, 6) }; + + std::vector actual; + + for (BresenhamLinePointer::iterator itr = bl.begin(); itr != bl.end(); ++itr) + { + actual.push_back(*itr); + } + + CHECK_EQUAL(expected.size(), bl.size()); + CHECK_EQUAL(expected.size(), actual.size()); + CHECK_ARRAY_EQUAL(expected.data(), actual.data(), (std::max(expected.size(), actual.size()))); + } + + //************************************************************************* + TEST(low_slope_diagonal_line_bottom_right_top_left) + { + Point first = { 9, 6 }; + Point last = { 0, 2 }; + + Value* first_ptr = GetPointer(first.x, first.y); + Value* last_ptr = GetPointer(last.x, last.y); + + BresenhamLinePointer bl(origin, stride, first.x, first.y, last.x, last.y); + + CHECK_EQUAL(first_ptr, bl.front()); + CHECK_EQUAL(last_ptr, bl.back()); + + std::vector expected { GetPointer(9, 6), GetPointer(8, 6), GetPointer(7, 5), GetPointer(6, 5), GetPointer(5, 4), + GetPointer(4, 4), GetPointer(3, 3), GetPointer(2, 3), GetPointer(1, 2), GetPointer(0, 2) }; + + std::vector actual; + + for (BresenhamLinePointer::iterator itr = bl.begin(); itr != bl.end(); ++itr) + { + actual.push_back(*itr); + } + + CHECK_EQUAL(expected.size(), bl.size()); + CHECK_EQUAL(expected.size(), actual.size()); + CHECK_ARRAY_EQUAL(expected.data(), actual.data(), (std::max(expected.size(), actual.size()))); + } + + //************************************************************************* + TEST(low_slope_diagonal_line_top_left_bottom_right) + { + Point first = { 0, 2 }; + Point last = { 9, 6 }; + + Value* first_ptr = GetPointer(first.x, first.y); + Value* last_ptr = GetPointer(last.x, last.y); + + BresenhamLinePointer bl(origin, stride, first.x, first.y, last.x, last.y); + + CHECK_EQUAL(first_ptr, bl.front()); + CHECK_EQUAL(last_ptr, bl.back()); + + std::vector expected { GetPointer(0, 2), GetPointer(1, 2), GetPointer(2, 3), GetPointer(3, 3), GetPointer(4, 4), + GetPointer(5, 4), GetPointer(6, 5), GetPointer(7, 5), GetPointer(8, 6), GetPointer(9, 6) }; + + std::vector actual; + + for (BresenhamLinePointer::iterator itr = bl.begin(); itr != bl.end(); ++itr) + { + actual.push_back(*itr); + } + + CHECK_EQUAL(expected.size(), bl.size()); + CHECK_EQUAL(expected.size(), actual.size()); + CHECK_ARRAY_EQUAL(expected.data(), actual.data(), (std::max(expected.size(), actual.size()))); + } + + //************************************************************************* + TEST(high_slope_diagonal_line_bottom_left_top_right) + { + Point first = { 2, 9 }; + Point last = { 6, 0 }; + + Value* first_ptr = GetPointer(first.x, first.y); + Value* last_ptr = GetPointer(last.x, last.y); + + BresenhamLinePointer bl(origin, stride, first.x, first.y, last.x, last.y); + + CHECK_EQUAL(first_ptr, bl.front()); + CHECK_EQUAL(last_ptr, bl.back()); + + std::vector expected { GetPointer(2, 9), GetPointer(2, 8), GetPointer(3, 7), GetPointer(3, 6), GetPointer(4, 5), + GetPointer(4, 4), GetPointer(5, 3), GetPointer(5, 2), GetPointer(6, 1), GetPointer(6, 0) }; + + std::vector actual; + + for (BresenhamLinePointer::iterator itr = bl.begin(); itr != bl.end(); ++itr) + { + actual.push_back(*itr); + } + + CHECK_EQUAL(expected.size(), bl.size()); + CHECK_EQUAL(expected.size(), actual.size()); + CHECK_ARRAY_EQUAL(expected.data(), actual.data(), (std::max(expected.size(), actual.size()))); + } + + //************************************************************************* + TEST(high_slope_diagonal_line_top_right_bottom_left) + { + Point first = { 6, 0 }; + Point last = { 2, 9 }; + + Value* first_ptr = GetPointer(first.x, first.y); + Value* last_ptr = GetPointer(last.x, last.y); + + BresenhamLinePointer bl(origin, stride, first.x, first.y, last.x, last.y); + + CHECK_EQUAL(first_ptr, bl.front()); + CHECK_EQUAL(last_ptr, bl.back()); + + std::vector expected { GetPointer(6, 0), GetPointer(6, 1), GetPointer(5, 2), GetPointer(5, 3), GetPointer(4, 4), + GetPointer(4, 5), GetPointer(3, 6), GetPointer(3, 7), GetPointer(2, 8), GetPointer(2, 9) }; + + std::vector actual; + + for (BresenhamLinePointer::iterator itr = bl.begin(); itr != bl.end(); ++itr) + { + actual.push_back(*itr); + } + + CHECK_EQUAL(expected.size(), bl.size()); + CHECK_EQUAL(expected.size(), actual.size()); + CHECK_ARRAY_EQUAL(expected.data(), actual.data(), (std::max(expected.size(), actual.size()))); + } + + //************************************************************************* + TEST(high_slope_diagonal_line_bottom_right_top_left) + { + Point first = { 6, 9}; + Point last = { 2, 0}; + + Value* first_ptr = GetPointer(first.x, first.y); + Value* last_ptr = GetPointer(last.x, last.y); + + BresenhamLinePointer bl(origin, stride, first.x, first.y, last.x, last.y); + + CHECK_EQUAL(first_ptr, bl.front()); + CHECK_EQUAL(last_ptr, bl.back()); + + std::vector expected { GetPointer(6, 9), GetPointer(6, 8), GetPointer(5, 7), GetPointer(5, 6), GetPointer(4, 5), + GetPointer(4, 4), GetPointer(3, 3), GetPointer(3, 2), GetPointer(2, 1), GetPointer(2, 0) }; + + std::vector actual; + + for (BresenhamLinePointer::iterator itr = bl.begin(); itr != bl.end(); ++itr) + { + actual.push_back(*itr); + } + + CHECK_EQUAL(expected.size(), bl.size()); + CHECK_EQUAL(expected.size(), actual.size()); + CHECK_ARRAY_EQUAL(expected.data(), actual.data(), (std::max(expected.size(), actual.size()))); + } + + //************************************************************************* + TEST(high_slope_diagonal_line_top_left_bottom_right) + { + Point first = { 2, 0 }; + Point last = { 6, 9 }; + + Value* first_ptr = GetPointer(first.x, first.y); + Value* last_ptr = GetPointer(last.x, last.y); + + BresenhamLinePointer bl(origin, stride, first.x, first.y, last.x, last.y); + + CHECK_EQUAL(first_ptr, bl.front()); + CHECK_EQUAL(last_ptr, bl.back()); + + std::vector expected { GetPointer(2, 0), GetPointer(2, 1), GetPointer(3, 2), GetPointer(3, 3), GetPointer(4, 4), + GetPointer(4, 5), GetPointer(5, 6), GetPointer(5, 7), GetPointer(6, 8), GetPointer(6, 9) }; + + std::vector actual; + + for (BresenhamLinePointer::iterator itr = bl.begin(); itr != bl.end(); ++itr) + { + actual.push_back(*itr); + } + + CHECK_EQUAL(expected.size(), bl.size()); + CHECK_EQUAL(expected.size(), actual.size()); + CHECK_ARRAY_EQUAL(expected.data(), actual.data(), (std::max(expected.size(), actual.size()))); + } + + //************************************************************************* + TEST(reset_the_line_from_individual_coordinates) + { + Point first = { 2, 0 }; + Point last = { 6, 9 }; + + Value* first_ptr = GetPointer(first.x, first.y); + Value* last_ptr = GetPointer(last.x, last.y); + + BresenhamLinePointer bl(origin, stride, first.x, first.y, last.x, last.y); + + CHECK_EQUAL(first_ptr, bl.front()); + CHECK_EQUAL(last_ptr, bl.back()); + + Point new_first = { 6, 9 }; + Point new_last = { 2, 0 }; + + bl.reset(new_first.x, new_first.y, new_last.x, new_last.y); + + std::vector expected { GetPointer(6, 9), GetPointer(6, 8), GetPointer(5, 7), GetPointer(5, 6), GetPointer(4, 5), + GetPointer(4, 4), GetPointer(3, 3), GetPointer(3, 2), GetPointer(2, 1), GetPointer(2, 0) }; + + std::vector actual; + + for (BresenhamLinePointer::iterator itr = bl.begin(); itr != bl.end(); ++itr) + { + actual.push_back(*itr); + } + + CHECK_EQUAL(expected.size(), bl.size()); + CHECK_EQUAL(expected.size(), actual.size()); + CHECK_ARRAY_EQUAL(expected.data(), actual.data(), (std::max(expected.size(), actual.size()))); + } + + //************************************************************************* + TEST(diagonal_line_write_read) + { + Point first = { 2, 0 }; + Point last = { 6, 9 }; + + Value* first_ptr = GetPointer(first.x, first.y); + Value* last_ptr = GetPointer(last.x, last.y); + + BresenhamLinePointer bl(origin, stride, first.x, first.y, last.x, last.y); + + CHECK_EQUAL(first_ptr, bl.front()); + CHECK_EQUAL(last_ptr, bl.back()); + + // Write 100 to the line elements. + for (auto itr : bl) + { + *itr = 100; + } + + // Read them back. + for (auto itr : bl) + { + CHECK_EQUAL(*itr, 100); + } + } + + //************************************************************************* + TEST(test_equality) + { + BresenhamLinePointer bl1(origin, stride, 0, 1, 2, 3); + BresenhamLinePointer bl2(origin, stride, 0, 1, 2, 3); + BresenhamLinePointer bl3(origin, stride, 0, 1, 2, 4); + BresenhamLinePointer bl4(origin, stride, 0, 2, 2, 3); + + CHECK(bl1 == bl2); + CHECK(!(bl1 != bl2)); + + CHECK(bl1 != bl3); + CHECK(!(bl1 == bl3)); + + CHECK(bl1 != bl4); + CHECK(!(bl1 == bl4)); + } + }; +} diff --git a/test/vs2019/etl.vcxproj b/test/vs2019/etl.vcxproj index a6306d81..b685a6c1 100644 --- a/test/vs2019/etl.vcxproj +++ b/test/vs2019/etl.vcxproj @@ -1252,6 +1252,7 @@ + @@ -4422,6 +4423,7 @@ + diff --git a/test/vs2019/etl.vcxproj.filters b/test/vs2019/etl.vcxproj.filters index 53249a88..7b2cf604 100644 --- a/test/vs2019/etl.vcxproj.filters +++ b/test/vs2019/etl.vcxproj.filters @@ -1104,6 +1104,9 @@ ETL\Maths + + ETL\Pseudo Containers + @@ -2525,6 +2528,9 @@ Source Files + + Source Files + From b8cbcb1925a3cbae851a9d3e66b9802ae02ddf06 Mon Sep 17 00:00:00 2001 From: John Wellbelove Date: Fri, 30 Apr 2021 18:17:49 +0100 Subject: [PATCH 06/18] Added etl::bresenham_line_iterator --- include/etl/bresenham_line.h | 54 ++++++++++++++------------ include/etl/utility.h | 2 + test/test_bresenham_line.cpp | 58 ++++++++++++++-------------- test/test_bresenham_line_pointer.cpp | 56 +++++++++++++-------------- 4 files changed, 88 insertions(+), 82 deletions(-) diff --git a/include/etl/bresenham_line.h b/include/etl/bresenham_line.h index 1016a7a5..28dd9e9f 100644 --- a/include/etl/bresenham_line.h +++ b/include/etl/bresenham_line.h @@ -56,12 +56,14 @@ namespace etl //*************************************************** /// Standard container types. //*************************************************** - typedef TCoordinate value_type; - typedef size_t size_type; - typedef value_type& reference; - typedef const value_type& const_reference; - typedef value_type* pointer; - typedef const value_type* const_pointer; + typedef TCoordinate value_type; + typedef TCoordinate coordinate_type; + typedef typename TCoordinate::value_type axis_type; + typedef size_t size_type; + typedef value_type& reference; + typedef const value_type& const_reference; + typedef value_type* pointer; + typedef const value_type* const_pointer; //*************************************************** /// Const Iterator @@ -120,7 +122,7 @@ namespace etl //*************************************************** /// De-reference operator //*************************************************** - value_type operator *() const + TCoordinate operator *() const { return p_bresenham_line->get_coordinate(); } @@ -146,27 +148,29 @@ namespace etl //*************************************************** /// Constructor for use by bresenham_line //*************************************************** - const_iterator(bresenham_line* pb) + const_iterator(bresenham_line* pb) : p_bresenham_line(pb) { } - bresenham_line* p_bresenham_line; + bresenham_line* p_bresenham_line; }; + friend class const_iterator; + //*************************************************** /// Constructor. //*************************************************** bresenham_line() { - initialise(TWork(0), TWork(0), TWork(0), TWork(0)); + initialise(axis_type(0), axis_type(0), axis_type(0), axis_type(0)); } //*************************************************** /// Constructor. /// Supplied first and last coordinates //*************************************************** - bresenham_line(value_type first_, value_type last_) + bresenham_line(coordinate_type first_, coordinate_type last_) { initialise(first_.x, first_.y, last_.x, last_.y); } @@ -175,7 +179,7 @@ namespace etl /// Constructor. /// Supplied first and last coordinates //*************************************************** - bresenham_line(TWork first_x, TWork first_y, TWork last_x, TWork last_y) + bresenham_line(axis_type first_x, axis_type first_y, axis_type last_x, axis_type last_y) { initialise(first_x, first_y, last_x, last_y); } @@ -184,7 +188,7 @@ namespace etl /// Resets the line. /// Supplied first and last coordinates //*************************************************** - void reset(value_type first_, value_type last_) + void reset(coordinate_type first_, coordinate_type last_) { initialise(first_.x, first_.y, last_.x, last_.y); } @@ -193,7 +197,7 @@ namespace etl /// Resets the line. /// Supplied first and last coordinates //*************************************************** - void reset(TWork first_x, TWork first_y, TWork last_x, TWork last_y) + void reset(axis_type first_x, axis_type first_y, axis_type last_x, axis_type last_y) { initialise(first_x, first_y, last_x, last_y); } @@ -269,10 +273,10 @@ namespace etl //*************************************************** /// Get the current number of generated points. //*************************************************** - void initialise(TWork first_x, TWork first_y, TWork last_x, TWork last_y) + void initialise(axis_type first_x, axis_type first_y, axis_type last_x, axis_type last_y) { - first = value_type(first_x, first_y); - last = value_type(last_x, last_y); + first = coordinate_type(first_x, first_y); + last = coordinate_type(last_x, last_y); coordinate = first; x_increment = (last_x < first_x) ? -1 : 1; y_increment = (last_y < first_y) ? -1 : 1; @@ -312,11 +316,11 @@ namespace etl // Y is major axis. if (do_minor_increment) { - coordinate.x = TWork(coordinate.x + x_increment); + coordinate.x = coordinate.x + x_increment; balance -= dy; } - coordinate.y = TWork(coordinate.y + y_increment); + coordinate.y = coordinate.y + y_increment; balance += dx; } else @@ -324,11 +328,11 @@ namespace etl // X is major axis. if (do_minor_increment) { - coordinate.y = TWork(coordinate.y + y_increment); + coordinate.y = coordinate.y + y_increment; balance -= dx; } - coordinate.x = TWork(coordinate.x + x_increment); + coordinate.x = coordinate.x + x_increment; balance += dy; } @@ -338,16 +342,16 @@ namespace etl //*************************************************** /// Get the current coordinate. //*************************************************** - value_type get_coordinate() const + coordinate_type get_coordinate() const { return coordinate; } typedef TWork work_t; - value_type first; - value_type last; - value_type coordinate; + coordinate_type first; + coordinate_type last; + coordinate_type coordinate; work_t x_increment; work_t y_increment; work_t dx; diff --git a/include/etl/utility.h b/include/etl/utility.h index 62d4237d..c37e3204 100644 --- a/include/etl/utility.h +++ b/include/etl/utility.h @@ -337,6 +337,8 @@ namespace etl template struct coordinate_2d { + typedef T value_type; + coordinate_2d() : x(T(0)) , y(T(0)) diff --git a/test/test_bresenham_line.cpp b/test/test_bresenham_line.cpp index 1e5d43b3..d6eaaad5 100644 --- a/test/test_bresenham_line.cpp +++ b/test/test_bresenham_line.cpp @@ -54,7 +54,7 @@ namespace return os; } - using BresenhamLine = etl::bresenham_line; + using BresenhamLine = etl::bresenham_line; SUITE(test_bresenham_line) { @@ -73,9 +73,9 @@ namespace Point{ 1, 5 }, Point{ 2, 5 }, Point{ 3, 5 }, Point{ 4, 5 }, Point{ 5, 5} }; std::vector actual; - for (BresenhamLine::const_iterator itr = bl.begin(); itr != bl.end(); ++itr) + for (auto p : bl) { - actual.push_back(*itr); + actual.push_back(p); } CHECK_EQUAL(expected.size(), bl.size()); @@ -98,9 +98,9 @@ namespace Point{-1, 5 }, Point{-2, 5 }, Point{-3, 5 }, Point{-4, 5 }, Point{-5, 5} }; std::vector actual; - for (BresenhamLine::const_iterator itr = bl.begin(); itr != bl.end(); ++itr) + for (auto p : bl) { - actual.push_back(*itr); + actual.push_back(p); } CHECK_EQUAL(expected.size(), bl.size()); @@ -123,9 +123,9 @@ namespace Point{ 5, 1 }, Point{ 5, 2 }, Point{ 5, 3 }, Point{ 5, 4 }, Point{ 5, 5} }; std::vector actual; - for (BresenhamLine::const_iterator itr = bl.begin(); itr != bl.end(); ++itr) + for (auto p : bl) { - actual.push_back(*itr); + actual.push_back(p); } CHECK_EQUAL(expected.size(), bl.size()); @@ -148,9 +148,9 @@ namespace Point{ 5, -1 }, Point{ 5, -2 }, Point{ 5, -3 }, Point{ 5, -4 }, Point{ 5, -5} }; std::vector actual; - for (BresenhamLine::const_iterator itr = bl.begin(); itr != bl.end(); ++itr) + for (auto p : bl) { - actual.push_back(*itr); + actual.push_back(p); } CHECK_EQUAL(expected.size(), bl.size()); @@ -173,9 +173,9 @@ namespace Point{ 1, 1 }, Point{ 2, 1 }, Point{ 3, 2 }, Point{ 4, 2 }, Point{ 5, 3 } }; std::vector actual; - for (BresenhamLine::const_iterator itr = bl.begin(); itr != bl.end(); ++itr) + for (auto p : bl) { - actual.push_back(*itr); + actual.push_back(p); } CHECK_EQUAL(expected.size(), bl.size()); @@ -198,9 +198,9 @@ namespace Point{ -1, -1 }, Point{ -2, -1 }, Point{ -3, -2 }, Point{ -4, -2 }, Point{ -5, -3 } }; std::vector actual; - for (BresenhamLine::const_iterator itr = bl.begin(); itr != bl.end(); ++itr) + for (auto p : bl) { - actual.push_back(*itr); + actual.push_back(p); } CHECK_EQUAL(expected.size(), bl.size()); @@ -223,9 +223,9 @@ namespace Point{ -1, 1 }, Point{ -2, 1 }, Point{ -3, 2 }, Point{ -4, 2 }, Point{ -5, 3 } }; std::vector actual; - for (BresenhamLine::const_iterator itr = bl.begin(); itr != bl.end(); ++itr) + for (auto p : bl) { - actual.push_back(*itr); + actual.push_back(p); } CHECK_EQUAL(expected.size(), bl.size()); @@ -248,9 +248,9 @@ namespace Point{ 1, -1 }, Point{ 2, -1 }, Point{ 3, -2 }, Point{ 4, -2 }, Point{ 5, -3 } }; std::vector actual; - for (BresenhamLine::const_iterator itr = bl.begin(); itr != bl.end(); ++itr) + for (auto p : bl) { - actual.push_back(*itr); + actual.push_back(p); } CHECK_EQUAL(expected.size(), bl.size()); @@ -273,9 +273,9 @@ namespace Point{ 1, 1 }, Point{ 1, 2 }, Point{ 2, 3 }, Point{ 2, 4 }, Point{ 3, 5 } }; std::vector actual; - for (BresenhamLine::const_iterator itr = bl.begin(); itr != bl.end(); ++itr) + for (auto p : bl) { - actual.push_back(*itr); + actual.push_back(p); } CHECK_EQUAL(expected.size(), bl.size()); @@ -298,9 +298,9 @@ namespace Point{ -1, -1 }, Point{ -1, -2 }, Point{ -2, -3 }, Point{ -2, -4 }, Point{ -3, -5 } }; std::vector actual; - for (BresenhamLine::const_iterator itr = bl.begin(); itr != bl.end(); ++itr) + for (auto p : bl) { - actual.push_back(*itr); + actual.push_back(p); } CHECK_EQUAL(expected.size(), bl.size()); @@ -323,9 +323,9 @@ namespace Point{ -1, 1 }, Point{ -1, 2 }, Point{ -2, 3 }, Point{ -2, 4 }, Point{ -3, 5 } }; std::vector actual; - for (BresenhamLine::const_iterator itr = bl.begin(); itr != bl.end(); ++itr) + for (auto p : bl) { - actual.push_back(*itr); + actual.push_back(p); } CHECK_EQUAL(expected.size(), bl.size()); @@ -348,9 +348,9 @@ namespace Point{ 1, -1 }, Point{ 1, -2 }, Point{ 2, -3 }, Point{ 2, -4 }, Point{ 3, -5 } }; std::vector actual; - for (BresenhamLine::const_iterator itr = bl.begin(); itr != bl.end(); ++itr) + for (auto p : bl) { - actual.push_back(*itr); + actual.push_back(p); } CHECK_EQUAL(expected.size(), bl.size()); @@ -378,9 +378,9 @@ namespace Point{ 1, -1 }, Point{ 1, -2 }, Point{ 2, -3 }, Point{ 2, -4 }, Point{ 3, -5 } }; std::vector actual; - for (BresenhamLine::const_iterator itr = bl.begin(); itr != bl.end(); ++itr) + for (auto p : bl) { - actual.push_back(*itr); + actual.push_back(p); } CHECK_EQUAL(expected.size(), bl.size()); @@ -405,9 +405,9 @@ namespace Point{ 1, -1 }, Point{ 1, -2 }, Point{ 2, -3 }, Point{ 2, -4 }, Point{ 3, -5 } }; std::vector actual; - for (BresenhamLine::const_iterator itr = bl.begin(); itr != bl.end(); ++itr) + for (auto p : bl) { - actual.push_back(*itr); + actual.push_back(p); } CHECK_EQUAL(expected.size(), bl.size()); diff --git a/test/test_bresenham_line_pointer.cpp b/test/test_bresenham_line_pointer.cpp index 047fe1a4..42c17ffe 100644 --- a/test/test_bresenham_line_pointer.cpp +++ b/test/test_bresenham_line_pointer.cpp @@ -129,9 +129,9 @@ namespace std::vector actual; - for (BresenhamLinePointer::iterator itr = bl.begin(); itr != bl.end(); ++itr) + for (auto p : bl) { - actual.push_back(*itr); + actual.push_back(p); } CHECK_EQUAL(expected.size(), bl.size()); @@ -158,9 +158,9 @@ namespace std::vector actual; - for (BresenhamLinePointerConst::iterator itr = bl.begin(); itr != bl.end(); ++itr) + for (auto p : bl) { - actual.push_back(*itr); + actual.push_back(p); } CHECK_EQUAL(expected.size(), bl.size()); @@ -187,9 +187,9 @@ namespace std::vector actual; - for (BresenhamLinePointer::iterator itr = bl.begin(); itr != bl.end(); ++itr) + for (auto p : bl) { - actual.push_back(*itr); + actual.push_back(p); } CHECK_EQUAL(expected.size(), bl.size()); @@ -216,9 +216,9 @@ namespace std::vector actual; - for (BresenhamLinePointer::iterator itr = bl.begin(); itr != bl.end(); ++itr) + for (auto p : bl) { - actual.push_back(*itr); + actual.push_back(p); } CHECK_EQUAL(expected.size(), bl.size()); @@ -245,9 +245,9 @@ namespace std::vector actual; - for (BresenhamLinePointer::iterator itr = bl.begin(); itr != bl.end(); ++itr) + for (auto p : bl) { - actual.push_back(*itr); + actual.push_back(p); } CHECK_EQUAL(expected.size(), bl.size()); @@ -274,9 +274,9 @@ namespace std::vector actual; - for (BresenhamLinePointer::iterator itr = bl.begin(); itr != bl.end(); ++itr) + for (auto p : bl) { - actual.push_back(*itr); + actual.push_back(p); } CHECK_EQUAL(expected.size(), bl.size()); @@ -303,9 +303,9 @@ namespace std::vector actual; - for (BresenhamLinePointer::iterator itr = bl.begin(); itr != bl.end(); ++itr) + for (auto p : bl) { - actual.push_back(*itr); + actual.push_back(p); } CHECK_EQUAL(expected.size(), bl.size()); @@ -332,9 +332,9 @@ namespace std::vector actual; - for (BresenhamLinePointer::iterator itr = bl.begin(); itr != bl.end(); ++itr) + for (auto p : bl) { - actual.push_back(*itr); + actual.push_back(p); } CHECK_EQUAL(expected.size(), bl.size()); @@ -361,9 +361,9 @@ namespace std::vector actual; - for (BresenhamLinePointer::iterator itr = bl.begin(); itr != bl.end(); ++itr) + for (auto p : bl) { - actual.push_back(*itr); + actual.push_back(p); } CHECK_EQUAL(expected.size(), bl.size()); @@ -390,9 +390,9 @@ namespace std::vector actual; - for (BresenhamLinePointer::iterator itr = bl.begin(); itr != bl.end(); ++itr) + for (auto p : bl) { - actual.push_back(*itr); + actual.push_back(p); } CHECK_EQUAL(expected.size(), bl.size()); @@ -419,9 +419,9 @@ namespace std::vector actual; - for (BresenhamLinePointer::iterator itr = bl.begin(); itr != bl.end(); ++itr) + for (auto p : bl) { - actual.push_back(*itr); + actual.push_back(p); } CHECK_EQUAL(expected.size(), bl.size()); @@ -448,9 +448,9 @@ namespace std::vector actual; - for (BresenhamLinePointer::iterator itr = bl.begin(); itr != bl.end(); ++itr) + for (auto p : bl) { - actual.push_back(*itr); + actual.push_back(p); } CHECK_EQUAL(expected.size(), bl.size()); @@ -477,9 +477,9 @@ namespace std::vector actual; - for (BresenhamLinePointer::iterator itr = bl.begin(); itr != bl.end(); ++itr) + for (auto p : bl) { - actual.push_back(*itr); + actual.push_back(p); } CHECK_EQUAL(expected.size(), bl.size()); @@ -511,9 +511,9 @@ namespace std::vector actual; - for (BresenhamLinePointer::iterator itr = bl.begin(); itr != bl.end(); ++itr) + for (auto p : bl) { - actual.push_back(*itr); + actual.push_back(p); } CHECK_EQUAL(expected.size(), bl.size()); From 358e2cb3d384a8cdca0db8d6cb465b51b508ae46 Mon Sep 17 00:00:00 2001 From: John Wellbelove Date: Fri, 30 Apr 2021 19:18:13 +0100 Subject: [PATCH 07/18] Added etl::singleton --- include/etl/singleton.h | 74 +++++++++++++++++++++++++++++++++ test/vs2019/etl.vcxproj | 1 + test/vs2019/etl.vcxproj.filters | 3 ++ 3 files changed, 78 insertions(+) create mode 100644 include/etl/singleton.h diff --git a/include/etl/singleton.h b/include/etl/singleton.h new file mode 100644 index 00000000..bbb900e9 --- /dev/null +++ b/include/etl/singleton.h @@ -0,0 +1,74 @@ +///\file + +/****************************************************************************** +The MIT License(MIT) + +Embedded Template Library. +https://github.com/ETLCPP/etl +https://www.etlcpp.com + +Copyright(c) 2021 jwellbelove + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files(the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and / or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions : + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. +******************************************************************************/ + +#ifndef ETL_SINGLETON_INCLUDED +#define ETL_SINGLETON_INCLUDED + +#include "platform.h" +#include "static_assert.h" +#include "type_traits.h" + +namespace etl +{ + //*************************************************************************** + /// Implementation of the Singleton pattern. + //*************************************************************************** + template + class singleton + { + public: + + //********************************* + /// Get the single instance of T. + //********************************* + static T& get() + { + ETL_STATIC_ASSERT((etl::is_base_of, T>::value), "T is not derived from etl::singleton"); + static T obj; + return obj; + } + + protected: + + singleton() {}; + virtual ~singleton() {}; + + // Deleted functions. + singleton(const singleton&) ETL_DELETE; + singleton& operator=(const singleton&) ETL_DELETE; + +#if ETL_CPP11_SUPPORTED + singleton(singleton&&) ETL_DELETE; + singleton& operator=(singleton&&) ETL_DELETE; +#endif + }; +} + +#endif diff --git a/test/vs2019/etl.vcxproj b/test/vs2019/etl.vcxproj index b685a6c1..7b232cd4 100644 --- a/test/vs2019/etl.vcxproj +++ b/test/vs2019/etl.vcxproj @@ -1381,6 +1381,7 @@ + diff --git a/test/vs2019/etl.vcxproj.filters b/test/vs2019/etl.vcxproj.filters index 7b2cf604..c534cf06 100644 --- a/test/vs2019/etl.vcxproj.filters +++ b/test/vs2019/etl.vcxproj.filters @@ -1107,6 +1107,9 @@ ETL\Pseudo Containers + + ETL\Patterns + From 64e22fac5ed0a47861ce7e1820c72c3056f17d6f Mon Sep 17 00:00:00 2001 From: John Wellbelove Date: Sat, 1 May 2021 19:10:33 +0100 Subject: [PATCH 08/18] Tests for etl::singleton & etl::for_each_iterator --- include/etl/algorithm.h | 3 +- include/etl/singleton.h | 8 ++-- test/test_algorithm.cpp | 25 ++++++++++++ test/test_singleton.cpp | 68 +++++++++++++++++++++++++++++++++ test/vs2019/etl.vcxproj | 1 + test/vs2019/etl.vcxproj.filters | 3 ++ 6 files changed, 102 insertions(+), 6 deletions(-) create mode 100644 test/test_singleton.cpp diff --git a/include/etl/algorithm.h b/include/etl/algorithm.h index b951975d..1a61cdb7 100644 --- a/include/etl/algorithm.h +++ b/include/etl/algorithm.h @@ -3085,8 +3085,7 @@ namespace etl ///\ingroup algorithm //*************************************************************************** template + typename TUnaryFunction> TUnaryFunction for_each_iterator(TIterator begin, const TIterator end, TUnaryFunction function) diff --git a/include/etl/singleton.h b/include/etl/singleton.h index bbb900e9..56e1458b 100644 --- a/include/etl/singleton.h +++ b/include/etl/singleton.h @@ -48,11 +48,11 @@ namespace etl //********************************* /// Get the single instance of T. //********************************* - static T& get() + static T& get_instance() { - ETL_STATIC_ASSERT((etl::is_base_of, T>::value), "T is not derived from etl::singleton"); - static T obj; - return obj; + ETL_STATIC_ASSERT((etl::is_base_of, T>::value), "T is not derived from etl::singleton"); + static T object; + return object; } protected: diff --git a/test/test_algorithm.cpp b/test/test_algorithm.cpp index 65bb4b6c..fabb31e0 100644 --- a/test/test_algorithm.cpp +++ b/test/test_algorithm.cpp @@ -2164,6 +2164,31 @@ namespace CHECK_EQUAL(std::accumulate(std::begin(data), std::end(data), 0), sum.value); } + //************************************************************************* + TEST(for_each_iterator) + { + int data[] = { 1, 8, 2, 7, 3, 6, 4, 5, 10, 9 }; + + struct Sum + { + void operator()(int* i) + { + value += *i; + } + + Sum() + : value(0) + { + } + + int value; + }; + + Sum sum; + sum = etl::for_each_iterator(std::begin(data), std::end(data), sum); + CHECK_EQUAL(std::accumulate(std::begin(data), std::end(data), 0), sum.value); + } + //************************************************************************* TEST(remove) { diff --git a/test/test_singleton.cpp b/test/test_singleton.cpp new file mode 100644 index 00000000..4d250b6f --- /dev/null +++ b/test/test_singleton.cpp @@ -0,0 +1,68 @@ +/****************************************************************************** +The MIT License(MIT) + +Embedded Template Library. +https://github.com/ETLCPP/etl +https://www.etlcpp.com + +Copyright(c) 2021 jwellbelove + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files(the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and / or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions : + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. +******************************************************************************/ + +#include "unit_test_framework.h" + +#include "etl/singleton.h" + +namespace +{ + class Test : public etl::singleton + { + public: + + using etl::singleton::get_instance; + + Test() + : called(false) + { + } + + void test() + { + called = true; + } + + bool called; + }; + + SUITE(test_singleton) + { + //************************************************************************* + TEST(test_instance) + { + ::Test& test1 = ::Test::get_instance(); + ::Test& test2 = ::Test::get_instance(); + + CHECK(&test1 == &test2); + + test1.test(); + CHECK(test1.called); + } + }; +} diff --git a/test/vs2019/etl.vcxproj b/test/vs2019/etl.vcxproj index 7b232cd4..fa377462 100644 --- a/test/vs2019/etl.vcxproj +++ b/test/vs2019/etl.vcxproj @@ -4905,6 +4905,7 @@ true true + diff --git a/test/vs2019/etl.vcxproj.filters b/test/vs2019/etl.vcxproj.filters index c534cf06..e0c71c96 100644 --- a/test/vs2019/etl.vcxproj.filters +++ b/test/vs2019/etl.vcxproj.filters @@ -2534,6 +2534,9 @@ Source Files + + Source Files + From 1ba1b03b0931b726f8cf106de7bb4fc9e48d8f5a Mon Sep 17 00:00:00 2001 From: John Wellbelove Date: Tue, 27 Apr 2021 18:21:44 +0100 Subject: [PATCH 09/18] Fixed incorrect histogram end() and cend() return values. --- include/etl/version.h | 2 +- library.json | 2 +- library.properties | 2 +- meson.build | 2 +- support/Release notes.txt | 4 ++++ 5 files changed, 8 insertions(+), 4 deletions(-) diff --git a/include/etl/version.h b/include/etl/version.h index 5a95ecd8..90d48476 100644 --- a/include/etl/version.h +++ b/include/etl/version.h @@ -39,7 +39,7 @@ SOFTWARE. #define ETL_VERSION_MAJOR 20 #define ETL_VERSION_MINOR 10 -#define ETL_VERSION_PATCH 0 +#define ETL_VERSION_PATCH 1 #define ETL_VERSION ETL_STRINGIFY(ETL_VERSION_MAJOR) "." ETL_STRINGIFY(ETL_VERSION_MINOR) "." ETL_STRINGIFY(ETL_VERSION_PATCH) #define ETL_VERSION_W ETL_STRINGIFY(ETL_VERSION_MAJOR) L"." ETL_STRINGIFY(ETL_VERSION_MINOR) L"." ETL_STRINGIFY(ETL_VERSION_PATCH) #define ETL_VERSION_U16 ETL_STRINGIFY(ETL_VERSION_MAJOR) u"." ETL_STRINGIFY(ETL_VERSION_MINOR) u"." ETL_STRINGIFY(ETL_VERSION_PATCH) diff --git a/library.json b/library.json index 5f1e835b..39c29e4b 100644 --- a/library.json +++ b/library.json @@ -1,6 +1,6 @@ { "name": "ETL Embedded Template Library", - "version": "20.10.0", + "version": "20.10.1", "author s": { "name": "John Wellbelove", "email": "john.wellbelove@etlcpp.com" diff --git a/library.properties b/library.properties index 295d134a..09899698 100644 --- a/library.properties +++ b/library.properties @@ -1,5 +1,5 @@ name=Embedded Template Library ETL -version=20.10.0 +version=20.10.1 author= John Wellbelove maintainer=John Wellbelove license=MIT diff --git a/meson.build b/meson.build index e5f24c8e..32663995 100644 --- a/meson.build +++ b/meson.build @@ -8,7 +8,7 @@ project('PROJECT_NAME', 'cpp_std=c++17', 'build.cpp_std=c++17', ], meson_version: '>=0.54.0', - version: '19.3.7' + version: '20.10.1' ) ###################### diff --git a/support/Release notes.txt b/support/Release notes.txt index 2d89550f..59712367 100644 --- a/support/Release notes.txt +++ b/support/Release notes.txt @@ -1,3 +1,7 @@ +=============================================================================== +20.10.1 +Fixed incorrect histogram end() and cend() return values. + =============================================================================== 20.10.0 Added Hierarchical Finite State Machine (etl::hfsm) derived from etl::fsm From 0b209e8d852cf624c1cecee3cf12675785d245c4 Mon Sep 17 00:00:00 2001 From: John Wellbelove Date: Mon, 10 May 2021 16:18:23 +0100 Subject: [PATCH 10/18] Fixed sparse histogram class name --- include/etl/histogram.h | 16 ++++++++-------- test/test_histogram.cpp | 2 +- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/include/etl/histogram.h b/include/etl/histogram.h index f2d0eefa..4e0d8fca 100644 --- a/include/etl/histogram.h +++ b/include/etl/histogram.h @@ -346,10 +346,10 @@ namespace etl }; //*************************************************************************** - /// Histogram for sparce keys. + /// Histogram for sparse keys. //*************************************************************************** template - class sparce_histogram : public etl::unary_function + class sparse_histogram : public etl::unary_function { private: @@ -371,7 +371,7 @@ namespace etl //********************************* /// Constructor //********************************* - sparce_histogram() + sparse_histogram() { } @@ -379,7 +379,7 @@ namespace etl /// Constructor //********************************* template - sparce_histogram(TIterator first, TIterator last) + sparse_histogram(TIterator first, TIterator last) { add(first, last); } @@ -387,7 +387,7 @@ namespace etl //********************************* /// Copy constructor //********************************* - sparce_histogram(const sparce_histogram& other) + sparse_histogram(const sparse_histogram& other) { this->accumulator = other.accumulator; } @@ -396,7 +396,7 @@ namespace etl //********************************* /// Move constructor //********************************* - sparce_histogram(sparce_histogram&& other) + sparse_histogram(sparse_histogram&& other) { accumulator = etl::move(other.accumulator); } @@ -405,7 +405,7 @@ namespace etl //********************************* /// Copy assignment //********************************* - sparce_histogram& operator =(const sparce_histogram& rhs) + sparse_histogram& operator =(const sparse_histogram& rhs) { accumulator = rhs.accumulator; @@ -416,7 +416,7 @@ namespace etl //********************************* /// Move assignment //********************************* - sparce_histogram& operator =(sparce_histogram&& rhs) + sparse_histogram& operator =(sparse_histogram&& rhs) { accumulator = etl::move(rhs.accumulator); diff --git a/test/test_histogram.cpp b/test/test_histogram.cpp index 1b53d3d8..fe87d82c 100644 --- a/test/test_histogram.cpp +++ b/test/test_histogram.cpp @@ -44,7 +44,7 @@ namespace using IntRuntimeOffsetHistogram = etl::histogram; using IntOffset0Histogram = etl::histogram; using IntOffsetminus4Histogram = etl::histogram; - using StringHistogram = etl::sparce_histogram; + using StringHistogram = etl::sparse_histogram; //*********************************** std::array input1 = From 0910ebda1bd5e6721fbeb7fbbab1c0167253f0e6 Mon Sep 17 00:00:00 2001 From: John Wellbelove Date: Mon, 10 May 2021 17:42:53 +0100 Subject: [PATCH 11/18] Updated versions --- include/etl/version.h | 2 +- library.json | 2 +- library.properties | 2 +- support/Release notes.txt | 4 ++++ 4 files changed, 7 insertions(+), 3 deletions(-) diff --git a/include/etl/version.h b/include/etl/version.h index 90d48476..14e810d6 100644 --- a/include/etl/version.h +++ b/include/etl/version.h @@ -39,7 +39,7 @@ SOFTWARE. #define ETL_VERSION_MAJOR 20 #define ETL_VERSION_MINOR 10 -#define ETL_VERSION_PATCH 1 +#define ETL_VERSION_PATCH 2 #define ETL_VERSION ETL_STRINGIFY(ETL_VERSION_MAJOR) "." ETL_STRINGIFY(ETL_VERSION_MINOR) "." ETL_STRINGIFY(ETL_VERSION_PATCH) #define ETL_VERSION_W ETL_STRINGIFY(ETL_VERSION_MAJOR) L"." ETL_STRINGIFY(ETL_VERSION_MINOR) L"." ETL_STRINGIFY(ETL_VERSION_PATCH) #define ETL_VERSION_U16 ETL_STRINGIFY(ETL_VERSION_MAJOR) u"." ETL_STRINGIFY(ETL_VERSION_MINOR) u"." ETL_STRINGIFY(ETL_VERSION_PATCH) diff --git a/library.json b/library.json index 39c29e4b..82857112 100644 --- a/library.json +++ b/library.json @@ -1,6 +1,6 @@ { "name": "ETL Embedded Template Library", - "version": "20.10.1", + "version": "20.10.2", "author s": { "name": "John Wellbelove", "email": "john.wellbelove@etlcpp.com" diff --git a/library.properties b/library.properties index 09899698..f3bf09bf 100644 --- a/library.properties +++ b/library.properties @@ -1,5 +1,5 @@ name=Embedded Template Library ETL -version=20.10.1 +version=20.10.2 author= John Wellbelove maintainer=John Wellbelove license=MIT diff --git a/support/Release notes.txt b/support/Release notes.txt index 59712367..f4560f6d 100644 --- a/support/Release notes.txt +++ b/support/Release notes.txt @@ -1,3 +1,7 @@ +=============================================================================== +20.10.2 +Fixed misspelled histogram class. + =============================================================================== 20.10.1 Fixed incorrect histogram end() and cend() return values. From 041b9534abd9e624b11b8fbfdb3aa5c3aad6ad32 Mon Sep 17 00:00:00 2001 From: John Wellbelove Date: Sun, 16 May 2021 10:57:44 +0100 Subject: [PATCH 12/18] Fixed FSM generation for non-default numbers message types. --- include/etl/fsm.h | 16 +++---- include/etl/generators/fsm_generator.h | 62 +++++++++++--------------- 2 files changed, 35 insertions(+), 43 deletions(-) diff --git a/include/etl/fsm.h b/include/etl/fsm.h index 2f71d587..cf1216eb 100644 --- a/include/etl/fsm.h +++ b/include/etl/fsm.h @@ -81,10 +81,10 @@ namespace etl typedef typename etl::larger_type::type fsm_internal_id_t; template + typename T1 = void, typename T2 = void, typename T3 = void, typename T4 = void, + typename T5 = void, typename T6 = void, typename T7 = void, typename T8 = void, + typename T9 = void, typename T10 = void, typename T11 = void, typename T12 = void, + typename T13 = void, typename T14 = void, typename T15 = void, typename T16 = void> class fsm_state; //*************************************************************************** @@ -179,10 +179,10 @@ namespace etl friend class etl::fsm; friend class etl::hfsm; template + typename, typename, typename, typename, + typename, typename, typename, typename, + typename, typename, typename, typename, + typename, typename, typename, typename> friend class etl::fsm_state; //******************************************* diff --git a/include/etl/generators/fsm_generator.h b/include/etl/generators/fsm_generator.h index 34fc133f..8bd67bb8 100644 --- a/include/etl/generators/fsm_generator.h +++ b/include/etl/generators/fsm_generator.h @@ -92,12 +92,19 @@ namespace etl // For internal FSM use. typedef typename etl::larger_type::type fsm_internal_id_t; - template - class fsm_state; + /*[[[cog + import cog + cog.outl("template " % int(Handlers)) + cog.outl("class fsm_state;") + ]]]*/ + /*[[[end]]]*/ //*************************************************************************** /// Base exception class for FSM. @@ -190,11 +197,18 @@ namespace etl /// Allows ifsm_state functions to be private. friend class etl::fsm; friend class etl::hfsm; - template + /*[[[cog + import cog + cog.outl(" template ") + ]]]*/ + /*[[[end]]]*/ friend class etl::fsm_state; //******************************************* @@ -207,6 +221,7 @@ namespace etl //******************************************* /// Adds a child to this state. + /// Only of use when part of an HFSM. //******************************************* void add_child_state(etl::ifsm_state& state) { @@ -222,6 +237,7 @@ namespace etl //******************************************* /// Adds a list of child states. + /// Only of use when part of an HFSM. //******************************************* template void set_child_states(etl::ifsm_state** state_list, TSize size) @@ -236,30 +252,6 @@ namespace etl } } - //******************************************* - /// Get the parent state for this state. - //******************************************* - etl::ifsm_state* get_parent_state() const - { - return p_parent; - } - - //******************************************* - /// Get the active child state for this state. - //******************************************* - etl::ifsm_state* get_active_child_state() const - { - return p_active_child; - } - - //******************************************* - /// Get the default child state for this state. - //******************************************* - etl::ifsm_state* get_default_child_state() const - { - return p_default_child; - } - protected: //******************************************* From 46dad1d1cb8e6c3660dca91db4a1c6cb35d778d2 Mon Sep 17 00:00:00 2001 From: John Wellbelove Date: Sun, 16 May 2021 11:12:28 +0100 Subject: [PATCH 13/18] Updated version numbers --- include/etl/version.h | 2 +- library.json | 2 +- library.properties | 2 +- meson.build | 2 +- support/Release notes.txt | 4 ++++ 5 files changed, 8 insertions(+), 4 deletions(-) diff --git a/include/etl/version.h b/include/etl/version.h index 14e810d6..65346fda 100644 --- a/include/etl/version.h +++ b/include/etl/version.h @@ -39,7 +39,7 @@ SOFTWARE. #define ETL_VERSION_MAJOR 20 #define ETL_VERSION_MINOR 10 -#define ETL_VERSION_PATCH 2 +#define ETL_VERSION_PATCH 3 #define ETL_VERSION ETL_STRINGIFY(ETL_VERSION_MAJOR) "." ETL_STRINGIFY(ETL_VERSION_MINOR) "." ETL_STRINGIFY(ETL_VERSION_PATCH) #define ETL_VERSION_W ETL_STRINGIFY(ETL_VERSION_MAJOR) L"." ETL_STRINGIFY(ETL_VERSION_MINOR) L"." ETL_STRINGIFY(ETL_VERSION_PATCH) #define ETL_VERSION_U16 ETL_STRINGIFY(ETL_VERSION_MAJOR) u"." ETL_STRINGIFY(ETL_VERSION_MINOR) u"." ETL_STRINGIFY(ETL_VERSION_PATCH) diff --git a/library.json b/library.json index 82857112..422bf5f6 100644 --- a/library.json +++ b/library.json @@ -1,6 +1,6 @@ { "name": "ETL Embedded Template Library", - "version": "20.10.2", + "version": "20.10.3", "author s": { "name": "John Wellbelove", "email": "john.wellbelove@etlcpp.com" diff --git a/library.properties b/library.properties index f3bf09bf..611779c6 100644 --- a/library.properties +++ b/library.properties @@ -1,5 +1,5 @@ name=Embedded Template Library ETL -version=20.10.2 +version=20.10.3 author= John Wellbelove maintainer=John Wellbelove license=MIT diff --git a/meson.build b/meson.build index 32663995..5bee70d4 100644 --- a/meson.build +++ b/meson.build @@ -8,7 +8,7 @@ project('PROJECT_NAME', 'cpp_std=c++17', 'build.cpp_std=c++17', ], meson_version: '>=0.54.0', - version: '20.10.1' + version: '20.10.3' ) ###################### diff --git a/support/Release notes.txt b/support/Release notes.txt index f4560f6d..f15ed693 100644 --- a/support/Release notes.txt +++ b/support/Release notes.txt @@ -1,3 +1,7 @@ +=============================================================================== +20.10.3 +Fixed etl::fsm generator for non-default number of message types. + =============================================================================== 20.10.2 Fixed misspelled histogram class. From 02b0bbae068dd3463d7cf441a40a741fe417f758 Mon Sep 17 00:00:00 2001 From: John Wellbelove Date: Sun, 16 May 2021 15:36:18 +0100 Subject: [PATCH 14/18] Added comment --- include/etl/successor.h | 1 + 1 file changed, 1 insertion(+) diff --git a/include/etl/successor.h b/include/etl/successor.h index 57377389..2d3ddddf 100644 --- a/include/etl/successor.h +++ b/include/etl/successor.h @@ -38,6 +38,7 @@ namespace etl { //*************************************************************************** /// Adds successor traits to a class. + /// Also known as 'Chain Of Responsibility'. //*************************************************************************** template class successor From 1d7fea289d8d11e10a058d947552d741e9f15b08 Mon Sep 17 00:00:00 2001 From: John Wellbelove Date: Tue, 18 May 2021 11:05:21 +0100 Subject: [PATCH 15/18] Fixed cross compiler compatibility for etl::circular_buffer. --- include/etl/circular_buffer.h | 2 +- include/etl/version.h | 2 +- library.json | 2 +- library.properties | 2 +- meson.build | 2 +- support/Release notes.txt | 4 ++++ 6 files changed, 9 insertions(+), 5 deletions(-) diff --git a/include/etl/circular_buffer.h b/include/etl/circular_buffer.h index c8026e92..d2470d83 100644 --- a/include/etl/circular_buffer.h +++ b/include/etl/circular_buffer.h @@ -965,7 +965,7 @@ namespace etl //************************************************************************* /// Protected constructor. //************************************************************************* - icircular_buffer(pointer pbuffer_, size_type max_length) + icircular_buffer(pointer pbuffer_, size_type max_length) : circular_buffer_base(max_length + 1U) , pbuffer(pbuffer_) { diff --git a/include/etl/version.h b/include/etl/version.h index 65346fda..3102f66c 100644 --- a/include/etl/version.h +++ b/include/etl/version.h @@ -39,7 +39,7 @@ SOFTWARE. #define ETL_VERSION_MAJOR 20 #define ETL_VERSION_MINOR 10 -#define ETL_VERSION_PATCH 3 +#define ETL_VERSION_PATCH 4 #define ETL_VERSION ETL_STRINGIFY(ETL_VERSION_MAJOR) "." ETL_STRINGIFY(ETL_VERSION_MINOR) "." ETL_STRINGIFY(ETL_VERSION_PATCH) #define ETL_VERSION_W ETL_STRINGIFY(ETL_VERSION_MAJOR) L"." ETL_STRINGIFY(ETL_VERSION_MINOR) L"." ETL_STRINGIFY(ETL_VERSION_PATCH) #define ETL_VERSION_U16 ETL_STRINGIFY(ETL_VERSION_MAJOR) u"." ETL_STRINGIFY(ETL_VERSION_MINOR) u"." ETL_STRINGIFY(ETL_VERSION_PATCH) diff --git a/library.json b/library.json index 422bf5f6..6aedee70 100644 --- a/library.json +++ b/library.json @@ -1,6 +1,6 @@ { "name": "ETL Embedded Template Library", - "version": "20.10.3", + "version": "20.10.4", "author s": { "name": "John Wellbelove", "email": "john.wellbelove@etlcpp.com" diff --git a/library.properties b/library.properties index 611779c6..c863da9b 100644 --- a/library.properties +++ b/library.properties @@ -1,5 +1,5 @@ name=Embedded Template Library ETL -version=20.10.3 +version=20.10.4 author= John Wellbelove maintainer=John Wellbelove license=MIT diff --git a/meson.build b/meson.build index 5bee70d4..04b64fe5 100644 --- a/meson.build +++ b/meson.build @@ -8,7 +8,7 @@ project('PROJECT_NAME', 'cpp_std=c++17', 'build.cpp_std=c++17', ], meson_version: '>=0.54.0', - version: '20.10.3' + version: '20.10.4' ) ###################### diff --git a/support/Release notes.txt b/support/Release notes.txt index f15ed693..5a7d19c9 100644 --- a/support/Release notes.txt +++ b/support/Release notes.txt @@ -1,3 +1,7 @@ +=============================================================================== +20.10.4 +Fixed cross compiler compatibility for etl::circular_buffer. + =============================================================================== 20.10.3 Fixed etl::fsm generator for non-default number of message types. From 2008434cf251ce0b02102b12511a95d1ad8075c4 Mon Sep 17 00:00:00 2001 From: John Wellbelove Date: Wed, 19 May 2021 15:06:41 +0100 Subject: [PATCH 16/18] center_of_gravity implementation --- include/etl/center_of_gravity.h | 207 +++++++++++++++++++++++++++ include/etl/scaled_rounding.h | 2 +- test/test_bresenham_line_pointer.cpp | 6 - test/test_center_of_gravity.cpp | 146 +++++++++++++++++++ test/vs2019/etl.vcxproj | 2 + test/vs2019/etl.vcxproj.filters | 9 ++ 6 files changed, 365 insertions(+), 7 deletions(-) create mode 100644 include/etl/center_of_gravity.h create mode 100644 test/test_center_of_gravity.cpp diff --git a/include/etl/center_of_gravity.h b/include/etl/center_of_gravity.h new file mode 100644 index 00000000..910a844a --- /dev/null +++ b/include/etl/center_of_gravity.h @@ -0,0 +1,207 @@ +///\file + +/****************************************************************************** +The MIT License(MIT) + +Embedded Template Library. +https://github.com/ETLCPP/etl +https://www.etlcpp.com + +Copyright(c) 2021 jwellbelove + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files(the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and / or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions : + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. +******************************************************************************/ + +#ifndef ETL_CENTER_OF_GRAVITY_INCLUDED +#define ETL_CENTER_OF_GRAVITY_INCLUDED + +#include "platform.h" +#include "functional.h" +#include "type_traits.h" +#include "scaled_rounding.h" + +namespace etl +{ + //*************************************************************************** + /// + //*************************************************************************** + template + class center_of_gravity + { + public: + + typedef TSum sum_type; + typedef TProduct product_type; + typedef TSample sample_type; + + //************************************************************************* + /// Constructor + //************************************************************************* + center_of_gravity() + : x_product(TProduct(0)) + , y_product(TProduct(0)) + , sum(TSum(0)) + { + + } + + //************************************************************************* + /// Add a new coordinate to the calculation. + //************************************************************************* + template + void add(TAxis x, TAxis y, TValue value) + { + x_product += (x * value); + y_product += (y * value); + sum += value; + } + + //************************************************************************* + /// Added a new coordinate to the calculation. + //************************************************************************* + template + void operator()(TAxis x, TAxis y, TValue value) + { + add(x, y, value); + } + + //************************************************************************* + /// Get the x coordinate of the center of gravity. + //************************************************************************* + template + typename etl::enable_if::value, T>::type + get_x() const + { + if (sum == T(0)) + { + return T(0); + } + else + { + return T(x_product) / T(sum); + } + } + + template + typename etl::enable_if::value, T>::type + get_x() const + { + if (sum == T(0)) + { + return T(0); + } + else + { + return static_cast(x_product / sum); + } + } + + template ::type Scale> + typename etl::enable_if::value, T>::type + get_x(T(*scaled_rounding)(T)) const + { + if (sum == T(0)) + { + return T(0); + } + else + { + return static_cast(scaled_rounding((Scale * x_product) / sum) / Scale); + } + } + + //************************************************************************* + /// Get the y coordinate of the center of gravity. + //************************************************************************* + template + typename etl::enable_if::value, T>::type + get_y() const + { + if (sum == T(0)) + { + return T(0); + } + else + { + return T(y_product) / T(sum); + } + } + + template + typename etl::enable_if::value, T>::type + get_y() const + { + if (sum == T(0)) + { + return T(0); + } + else + { + return static_cast(y_product / sum); + } + } + + template ::type Scale> + typename etl::enable_if::value, T>::type + get_y(T(*scaled_rounding)(T)) const + { + if (sum == T(0)) + { + return T(0); + } + else + { + return static_cast(scaled_rounding((Scale * y_product) / sum) / Scale); + } + } + + //************************************************************************* + /// Get the coordinate of the center of gravity. + //************************************************************************* + template + TCoordinate get() const + { + return TCoordinate(get_x(), get_y()); + } + + template ::type Scale> + TCoordinate get(TAxis(*scaled_rounding)(TAxis)) const + { + return TCoordinate(get_x(scaled_rounding), get_y(scaled_rounding)); + } + + //************************************************************************* + /// Clear the center of gravity calculation. + //************************************************************************* + void clear() + { + x_product = TProduct(0); + y_product = TProduct(0); + sum = TSum(0); + } + + private: + + TProduct x_product; + TProduct y_product; + TSum sum; + }; +} + +#endif diff --git a/include/etl/scaled_rounding.h b/include/etl/scaled_rounding.h index bef1d15a..279708cd 100644 --- a/include/etl/scaled_rounding.h +++ b/include/etl/scaled_rounding.h @@ -44,7 +44,7 @@ namespace etl typedef typename etl::conditional::value, int32_t, uint32_t>::type type; }; - //***************************************************************************** + //***************************************************************************** /// A set of rounding algorithms for scaled integrals. /// \tparam T The integral type. /// \tparam SCALING The scaling factor. diff --git a/test/test_bresenham_line_pointer.cpp b/test/test_bresenham_line_pointer.cpp index 42c17ffe..6e5bafc5 100644 --- a/test/test_bresenham_line_pointer.cpp +++ b/test/test_bresenham_line_pointer.cpp @@ -95,12 +95,6 @@ namespace return &const_image[y][x]; } - // Convert a coordinate to an expected value. - constexpr Value GetValue(Value x, Value y) - { - return (x + (y * 10)); - } - Value* origin = &image[0][0]; const Value* const_origin = &const_image[0][0]; constexpr size_t stride = image.size(); diff --git a/test/test_center_of_gravity.cpp b/test/test_center_of_gravity.cpp new file mode 100644 index 00000000..22532495 --- /dev/null +++ b/test/test_center_of_gravity.cpp @@ -0,0 +1,146 @@ +///****************************************************************************** +//The MIT License(MIT) +// +//Embedded Template Library. +//https://github.com/ETLCPP/etl +//https://www.etlcpp.com +// +//Copyright(c) 2021 jwellbelove +// +//Permission is hereby granted, free of charge, to any person obtaining a copy +//of this software and associated documentation files(the "Software"), to deal +//in the Software without restriction, including without limitation the rights +//to use, copy, modify, merge, publish, distribute, sublicense, and / or sell +//copies of the Software, and to permit persons to whom the Software is +//furnished to do so, subject to the following conditions : +// +//The above copyright notice and this permission notice shall be included in all +//copies or substantial portions of the Software. +// +//THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +//IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +//FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE +//AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +//LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +//OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +//SOFTWARE. +//******************************************************************************/ + +#include "unit_test_framework.h" + +#include "etl/center_of_gravity.h" +#include "etl/utility.h" +#include "etl/scaled_rounding.h" + +#include + +namespace +{ + using Cog = etl::center_of_gravity; + + //*********************************** + struct Point + { + int x; + int y; + uint8_t value; + }; + + //*********************************** + std::vector points = + { + { 31, 21, 1 }, { 40, 21, 1 }, { 31, 30, 1 }, { 40, 30, 1 }, + { 21, 11, 2 }, { 21, 40, 2 }, { 50, 11, 2 }, { 50, 40, 2 }, + }; + + //*********************************** + struct Proxy + { + void operator()(Point point) + { + cog(point.x, point.y, point.value); + } + + Cog& cog; + }; + + SUITE(test_center_of_gravity) + { + //************************************************************************* + TEST(test_default_constructor) + { + Cog cog; + + CHECK_EQUAL(0, cog.get_x()); + CHECK_EQUAL(0, cog.get_y()); + CHECK_EQUAL(0.0, cog.get_x()); + CHECK_EQUAL(0.0, cog.get_y()); + CHECK((std::pair(0, 0)) == (cog.get, int>())); + CHECK((etl::coordinate_2d(0, 0)) == (cog.get>())); + } + + //************************************************************************* + TEST(test_all_same_coordinates) + { + Cog cog; + + for (int i = 0; i < 10; ++i) + { + cog(1, 2, 3); + } + + CHECK_EQUAL(1, cog.get_x()); + CHECK_EQUAL(2, cog.get_y()); + CHECK_EQUAL(1.0, cog.get_x()); + CHECK_EQUAL(2.0, cog.get_y()); + CHECK((std::pair(1, 2)) == (cog.get, int>())); + CHECK((std::pair(1.0, 2.0)) == (cog.get, double>())); + CHECK((etl::coordinate_2d(1, 2)) == (cog.get>())); + CHECK((etl::coordinate_2d(1, 2)) == (cog.get>())); + } + + //************************************************************************* + TEST(test_vector_of_coordinates) + { + Cog cog; + Proxy proxy{ cog }; + using coordi = etl::coordinate_2d; + using coordd = etl::coordinate_2d; + + for (const auto& point : points) + { + proxy(point); + } + + CHECK_EQUAL(35, cog.get_x()); + CHECK_EQUAL(25, cog.get_y()); + + CHECK_EQUAL(35.5, cog.get_x()); + CHECK_EQUAL(25.5, cog.get_y()); + + CHECK((coordi(35, 25)) == (cog.get())); + CHECK((coordd(35.5, 25.5)) == (cog.get())); + } + + //************************************************************************* + TEST(test_vector_of_coordinates_with_round_half_up) + { + Cog cog; + Proxy proxy{ cog }; + using coord = etl::coordinate_2d; + + for (const auto& point : points) + { + proxy(point); + } + + constexpr int Scale = 10; + + int(*rounding)(int) = &etl::round_half_up_scaled; + + CHECK_EQUAL(36, (cog.get_x(rounding))); + CHECK_EQUAL(26, (cog.get_y(rounding))); + CHECK((coord(36, 26)) == (cog.get(rounding))); + } + }; +} diff --git a/test/vs2019/etl.vcxproj b/test/vs2019/etl.vcxproj index fa377462..23a9e933 100644 --- a/test/vs2019/etl.vcxproj +++ b/test/vs2019/etl.vcxproj @@ -1255,6 +1255,7 @@ + @@ -4427,6 +4428,7 @@ + diff --git a/test/vs2019/etl.vcxproj.filters b/test/vs2019/etl.vcxproj.filters index e0c71c96..dde98b11 100644 --- a/test/vs2019/etl.vcxproj.filters +++ b/test/vs2019/etl.vcxproj.filters @@ -106,6 +106,9 @@ {562466b5-677d-4448-9e9e-f70805cd71ad} + + {e2e177cb-de61-4c55-90ce-56b8b60343fa} + @@ -1110,6 +1113,9 @@ ETL\Patterns + + ETL\Graphical + @@ -2537,6 +2543,9 @@ Source Files + + Source Files + From 54e578415b16ef5a9a8f44a98f8d372a7805746e Mon Sep 17 00:00:00 2001 From: John Wellbelove Date: Thu, 20 May 2021 19:29:52 +0100 Subject: [PATCH 17/18] Add coordinates as a separate header --- include/etl/bresenham_line.h | 16 +- include/etl/center_of_gravity_1d.h | 151 +++++++ ...er_of_gravity.h => center_of_gravity_2d.h} | 60 ++- include/etl/center_of_gravity_3d.h | 298 ++++++++++++ include/etl/coordinate.h | 427 ++++++++++++++++++ include/etl/utility.h | 34 +- test/test_atomic_std.cpp | 8 +- test/test_center_of_gravity_1d.cpp | 111 +++++ ...vity.cpp => test_center_of_gravity_2d.cpp} | 40 +- test/test_center_of_gravity_3d.cpp | 136 ++++++ test/test_coordinate.cpp | 329 ++++++++++++++ test/vs2019/etl.vcxproj | 10 +- test/vs2019/etl.vcxproj.filters | 22 +- 13 files changed, 1554 insertions(+), 88 deletions(-) create mode 100644 include/etl/center_of_gravity_1d.h rename include/etl/{center_of_gravity.h => center_of_gravity_2d.h} (74%) create mode 100644 include/etl/center_of_gravity_3d.h create mode 100644 include/etl/coordinate.h create mode 100644 test/test_center_of_gravity_1d.cpp rename test/{test_center_of_gravity.cpp => test_center_of_gravity_2d.cpp} (84%) create mode 100644 test/test_center_of_gravity_3d.cpp create mode 100644 test/test_coordinate.cpp diff --git a/include/etl/bresenham_line.h b/include/etl/bresenham_line.h index 28dd9e9f..343aa58a 100644 --- a/include/etl/bresenham_line.h +++ b/include/etl/bresenham_line.h @@ -56,14 +56,14 @@ namespace etl //*************************************************** /// Standard container types. //*************************************************** - typedef TCoordinate value_type; - typedef TCoordinate coordinate_type; - typedef typename TCoordinate::value_type axis_type; - typedef size_t size_type; - typedef value_type& reference; - typedef const value_type& const_reference; - typedef value_type* pointer; - typedef const value_type* const_pointer; + typedef TCoordinate value_type; + typedef TCoordinate coordinate_type; + typedef typename TCoordinate::axis_type axis_type; + typedef size_t size_type; + typedef value_type& reference; + typedef const value_type& const_reference; + typedef value_type* pointer; + typedef const value_type* const_pointer; //*************************************************** /// Const Iterator diff --git a/include/etl/center_of_gravity_1d.h b/include/etl/center_of_gravity_1d.h new file mode 100644 index 00000000..3f409698 --- /dev/null +++ b/include/etl/center_of_gravity_1d.h @@ -0,0 +1,151 @@ +///\file + +/****************************************************************************** +The MIT License(MIT) + +Embedded Template Library. +https://github.com/ETLCPP/etl +https://www.etlcpp.com + +Copyright(c) 2021 jwellbelove + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files(the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and / or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions : + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. +******************************************************************************/ + +#ifndef ETL_CENTER_OF_GRAVITY_1D_INCLUDED +#define ETL_CENTER_OF_GRAVITY_1D_INCLUDED + +#include "platform.h" +#include "functional.h" +#include "type_traits.h" +#include "scaled_rounding.h" + +namespace etl +{ + //*************************************************************************** + /// + //*************************************************************************** + template + class center_of_gravity_1d + { + public: + + typedef TSum sum_type; + typedef TProduct product_type; + + //************************************************************************* + /// Constructor + //************************************************************************* + center_of_gravity_1d() + : product(TProduct(0)) + , sum(TSum(0)) + { + + } + + //************************************************************************* + /// Add a new coordinate to the calculation. + //************************************************************************* + template + void add(TAxis x, TValue value = TValue(1)) + { + product += (x * value); + sum += value; + } + + //************************************************************************* + /// Added a new coordinate to the calculation. + //************************************************************************* + template + void operator()(TAxis x, TValue value = TValue(1)) + { + add(x, value); + } + + //************************************************************************* + /// Get the x coordinate of the center of gravity. + /// Floating point. + //************************************************************************* + template + typename etl::enable_if::value, T>::type + get() const + { + if (sum == T(0)) + { + return T(0); + } + else + { + return T(product) / T(sum); + } + } + + //************************************************************************* + /// Get the x coordinate of the center of gravity. + /// Not floating point. + //************************************************************************* + template + typename etl::enable_if::value, T>::type + get() const + { + if (sum == T(0)) + { + return T(0); + } + else + { + return static_cast(product / sum); + } + } + + //************************************************************************* + /// Get the x coordinate of the center of gravity. + /// Not floating point, rounding. + //************************************************************************* + template ::type Scale> + typename etl::enable_if::value, T>::type + get(T(*scaled_rounding)(T)) const + { + if (sum == T(0)) + { + return T(0); + } + else + { + return static_cast(scaled_rounding((Scale * product) / sum) / Scale); + } + } + + //************************************************************************* + /// Clear the center of gravity calculation. + //************************************************************************* + void clear() + { + product = TProduct(0); + sum = TSum(0); + } + + private: + + TProduct product; + TSum sum; + }; +} + +#endif diff --git a/include/etl/center_of_gravity.h b/include/etl/center_of_gravity_2d.h similarity index 74% rename from include/etl/center_of_gravity.h rename to include/etl/center_of_gravity_2d.h index 910a844a..8f6fd173 100644 --- a/include/etl/center_of_gravity.h +++ b/include/etl/center_of_gravity_2d.h @@ -28,32 +28,32 @@ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ******************************************************************************/ -#ifndef ETL_CENTER_OF_GRAVITY_INCLUDED -#define ETL_CENTER_OF_GRAVITY_INCLUDED +#ifndef ETL_CENTER_OF_GRAVITY_2D_INCLUDED +#define ETL_CENTER_OF_GRAVITY_2D_INCLUDED #include "platform.h" #include "functional.h" #include "type_traits.h" #include "scaled_rounding.h" +#include "utility.h" namespace etl { //*************************************************************************** /// //*************************************************************************** - template - class center_of_gravity + template + class center_of_gravity_2d { public: typedef TSum sum_type; typedef TProduct product_type; - typedef TSample sample_type; //************************************************************************* /// Constructor //************************************************************************* - center_of_gravity() + center_of_gravity_2d() : x_product(TProduct(0)) , y_product(TProduct(0)) , sum(TSum(0)) @@ -65,22 +65,62 @@ namespace etl /// Add a new coordinate to the calculation. //************************************************************************* template - void add(TAxis x, TAxis y, TValue value) + void add(TAxis x, TAxis y, TValue value = TValue(1)) { x_product += (x * value); y_product += (y * value); sum += value; } + //************************************************************************* + /// Add a new coordinate to the calculation. + //************************************************************************* + template + void add(etl::coordinate_2d coord, TValue value = TValue(1)) + { + x_product += (coord.x * value); + y_product += (coord.y * value); + sum += value; + } + + //************************************************************************* + /// Add a new coordinate to the calculation. + //************************************************************************* + template + void add(etl::coordinate_2d coord) + { + x_product += (coord.x * coord.value); + y_product += (coord.y * coord.value); + sum += coord.value; + } + //************************************************************************* /// Added a new coordinate to the calculation. //************************************************************************* template - void operator()(TAxis x, TAxis y, TValue value) + void operator()(TAxis x, TAxis y, TValue value = TValue(1)) { add(x, y, value); } + //************************************************************************* + /// Added a new coordinate to the calculation. + //************************************************************************* + template + void operator()(etl::coordinate_2d coord, TValue value = TValue(1)) + { + add(coord, value); + } + + //************************************************************************* + /// Added a new coordinate to the calculation. + //************************************************************************* + template + void operator()(etl::coordinate_2d coord) + { + add(coord); + } + //************************************************************************* /// Get the x coordinate of the center of gravity. //************************************************************************* @@ -174,13 +214,13 @@ namespace etl //************************************************************************* /// Get the coordinate of the center of gravity. //************************************************************************* - template + template TCoordinate get() const { return TCoordinate(get_x(), get_y()); } - template ::type Scale> + template ::type Scale> TCoordinate get(TAxis(*scaled_rounding)(TAxis)) const { return TCoordinate(get_x(scaled_rounding), get_y(scaled_rounding)); diff --git a/include/etl/center_of_gravity_3d.h b/include/etl/center_of_gravity_3d.h new file mode 100644 index 00000000..fcc56254 --- /dev/null +++ b/include/etl/center_of_gravity_3d.h @@ -0,0 +1,298 @@ +///\file + +/****************************************************************************** +The MIT License(MIT) + +Embedded Template Library. +https://github.com/ETLCPP/etl +https://www.etlcpp.com + +Copyright(c) 2021 jwellbelove + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files(the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and / or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions : + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. +******************************************************************************/ + +#ifndef ETL_CENTER_OF_GRAVITY_3D_INCLUDED +#define ETL_CENTER_OF_GRAVITY_3D_INCLUDED + +#include "platform.h" +#include "functional.h" +#include "type_traits.h" +#include "scaled_rounding.h" +#include "utility.h" + +namespace etl +{ + //*************************************************************************** + /// + //*************************************************************************** + template + class center_of_gravity_3d + { + public: + + typedef TSum sum_type; + typedef TProduct product_type; + + //************************************************************************* + /// Constructor + //************************************************************************* + center_of_gravity_3d() + : x_product(TProduct(0)) + , y_product(TProduct(0)) + , z_product(TProduct(0)) + , sum(TSum(0)) + { + + } + + //************************************************************************* + /// Add a new coordinate to the calculation. + //************************************************************************* + template + void add(TAxis x, TAxis y, TAxis z, TValue value = TValue(1)) + { + x_product += (x * value); + y_product += (y * value); + z_product += (z * value); + sum += value; + } + + //************************************************************************* + /// Add a new coordinate to the calculation. + //************************************************************************* + template + void add(etl::coordinate_3d coord, TValue value = TValue(1)) + { + x_product += (coord.x * value); + y_product += (coord.y * value); + z_product += (coord.z * value); + sum += value; + } + + //************************************************************************* + /// Add a new coordinate to the calculation. + //************************************************************************* + template + void add(etl::coordinate_3d coord) + { + x_product += (coord.x * coord.value); + y_product += (coord.y * coord.value); + z_product += (coord.z * coord.value); + sum += coord.value; + } + + //************************************************************************* + /// Added a new coordinate to the calculation. + //************************************************************************* + template + void operator()(TAxis x, TAxis y, TAxis z, TValue value = TValue(1)) + { + add(x, y, z, value); + } + + //************************************************************************* + /// Added a new coordinate to the calculation. + //************************************************************************* + template + void operator()(etl::coordinate_3d coord, TValue value = TValue(1)) + { + add(coord, value); + } + + //************************************************************************* + /// Added a new coordinate to the calculation. + //************************************************************************* + template + void operator()(etl::coordinate_3d coord) + { + add(coord); + } + + //************************************************************************* + /// Get the x coordinate of the center of gravity. + //************************************************************************* + template + typename etl::enable_if::value, T>::type + get_x() const + { + if (sum == T(0)) + { + return T(0); + } + else + { + return T(x_product) / T(sum); + } + } + + template + typename etl::enable_if::value, T>::type + get_x() const + { + if (sum == T(0)) + { + return T(0); + } + else + { + return static_cast(x_product / sum); + } + } + + template ::type Scale> + typename etl::enable_if::value, T>::type + get_x(T(*scaled_rounding)(T)) const + { + if (sum == T(0)) + { + return T(0); + } + else + { + return static_cast(scaled_rounding((Scale * x_product) / sum) / Scale); + } + } + + //************************************************************************* + /// Get the y coordinate of the center of gravity. + //************************************************************************* + template + typename etl::enable_if::value, T>::type + get_y() const + { + if (sum == T(0)) + { + return T(0); + } + else + { + return T(y_product) / T(sum); + } + } + + template + typename etl::enable_if::value, T>::type + get_y() const + { + if (sum == T(0)) + { + return T(0); + } + else + { + return static_cast(y_product / sum); + } + } + + template ::type Scale> + typename etl::enable_if::value, T>::type + get_y(T(*scaled_rounding)(T)) const + { + if (sum == T(0)) + { + return T(0); + } + else + { + return static_cast(scaled_rounding((Scale * y_product) / sum) / Scale); + } + } + + //************************************************************************* + /// Get the z coordinate of the center of gravity. + //************************************************************************* + template + typename etl::enable_if::value, T>::type + get_z() const + { + if (sum == T(0)) + { + return T(0); + } + else + { + return T(z_product) / T(sum); + } + } + + template + typename etl::enable_if::value, T>::type + get_z() const + { + if (sum == T(0)) + { + return T(0); + } + else + { + return static_cast(z_product / sum); + } + } + + template ::type Scale> + typename etl::enable_if::value, T>::type + get_z(T(*scaled_rounding)(T)) const + { + if (sum == T(0)) + { + return T(0); + } + else + { + return static_cast(scaled_rounding((Scale * y_product) / sum) / Scale); + } + } + + //************************************************************************* + /// Get the coordinate of the center of gravity. + //************************************************************************* + template + TCoordinate get() const + { + return TCoordinate(get_x(), get_y(), get_z()); + } + + template ::type Scale> + TCoordinate get(TAxis(*scaled_rounding)(TAxis)) const + { + return TCoordinate(get_x(scaled_rounding), get_y(scaled_rounding), get_z(scaled_rounding)); + } + + //************************************************************************* + /// Clear the center of gravity calculation. + //************************************************************************* + void clear() + { + x_product = TProduct(0); + y_product = TProduct(0); + z_product = TProduct(0); + sum = TSum(0); + } + + private: + + TProduct x_product; + TProduct y_product; + TProduct z_product; + TSum sum; + }; +} + +#endif diff --git a/include/etl/coordinate.h b/include/etl/coordinate.h new file mode 100644 index 00000000..a860dfef --- /dev/null +++ b/include/etl/coordinate.h @@ -0,0 +1,427 @@ +///\file + +/****************************************************************************** +The MIT License(MIT) + +Embedded Template Library. +https://github.com/ETLCPP/etl +https://www.etlcpp.com + +Copyright(c) 2021 jwellbelove + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files(the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and / or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions : + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. +******************************************************************************/ + +#ifndef ETL_COORDINATE_INCLUDED +#define ETL_COORDINATE_INCLUDED + +#include "platform.h" + +///\defgroup coordinate coordinate +///\ingroup coordinate + +namespace etl +{ + //****************************************************************************** + /// 2D coordinate type with value. + template + struct coordinate_2d + { + typedef TValue value_type; + typedef TAxis axis_type; + + //*********************************** + coordinate_2d() + : x(TAxis(0)) + , y(TAxis(0)) + , value(TValue(0)) + { + } + + //*********************************** + coordinate_2d(TAxis x_, TAxis y_) + : x(x_) + , y(y_) + , value(TValue(0)) + { + } + + //*********************************** + coordinate_2d(TAxis x_, TAxis y_, TValue value_) + : x(x_) + , y(y_) + , value(value_) + { + } + + //*********************************** + coordinate_2d& operator =(etl::coordinate_2d other) + { + x = other.x; + y = other.y; + value = TValue(0); + + return *this; + } + + //*********************************** + coordinate_2d& operator +=(const coordinate_2d& rhs) + { + x += rhs.x; + y += rhs.y; + + return *this; + } + + //*********************************** + coordinate_2d& operator -=(const coordinate_2d& rhs) + { + x -= rhs.x; + y -= rhs.y; + + return *this; + } + + TAxis x; + TAxis y; + TValue value; + }; + + //****************************************************************************** + /// 2D coordinate type. + template + struct coordinate_2d + { + typedef void value_type; + typedef TAxis axis_type; + + //*********************************** + coordinate_2d() + : x(TAxis(0)) + , y(TAxis(0)) + { + } + + //*********************************** + coordinate_2d(TAxis x_, TAxis y_) + : x(x_) + , y(y_) + { + } + + //*********************************** + coordinate_2d(const coordinate_2d& other) + : x(other.x) + , y(other.y) + { + } + + //*********************************** + coordinate_2d& operator =(const coordinate_2d& other) + { + x = other.x; + y = other.y; + + return *this; + } + + //*********************************** + coordinate_2d& operator +=(const coordinate_2d& rhs) + { + x += rhs.x; + y += rhs.y; + + return *this; + } + + //*********************************** + coordinate_2d& operator -=(const coordinate_2d& rhs) + { + x -= rhs.x; + y -= rhs.y; + + return *this; + } + + TAxis x; + TAxis y; + }; + + //****************************************************************************** + /// 3D coordinate type with value. + template + struct coordinate_3d + { + typedef TValue value_type; + typedef TAxis axis_type; + + //*********************************** + coordinate_3d() + : x(TAxis(0)) + , y(TAxis(0)) + , z(TAxis(0)) + , value(TValue(0)) + { + } + + //*********************************** + coordinate_3d(TAxis x_, TAxis y_, TAxis z_, TValue value_) + : x(x_) + , y(y_) + , z(z_) + , value(value_) + { + } + + //*********************************** + coordinate_3d(TAxis x_, TAxis y_, TAxis z_) + : x(x_) + , y(y_) + , z(z_) + , value(TValue(0)) + { + } + + //*********************************** + coordinate_3d(const coordinate_3d& other) + : x(other.x) + , y(other.y) + , z(other.z) + , value(other.value) + { + } + + //*********************************** + coordinate_3d& operator =(const coordinate_3d& other) + { + x = other.x; + y = other.y; + z = other.z; + value = other.value; + + return *this; + } + + //*********************************** + coordinate_3d& operator +=(const coordinate_3d& rhs) + { + x += rhs.x; + y += rhs.y; + z += rhs.z; + + return *this; + } + + //*********************************** + coordinate_3d& operator -=(const coordinate_3d& rhs) + { + x -= rhs.x; + y -= rhs.y; + z -= rhs.z; + + return *this; + } + + TAxis x; + TAxis y; + TAxis z; + TValue value; + }; + + //****************************************************************************** + /// 3D coordinate type. + template + struct coordinate_3d + { + typedef void value_type; + typedef TAxis axis_type; + + //*********************************** + coordinate_3d() + : x(TAxis(0)) + , y(TAxis(0)) + , z(TAxis(0)) + { + } + + //*********************************** + coordinate_3d(TAxis x_, TAxis y_, TAxis z_) + : x(x_) + , y(y_) + , z(z_) + { + } + + //*********************************** + coordinate_3d(const coordinate_3d& other) + : x(other.x) + , y(other.y) + , z(other.z) + { + } + + //*********************************** + template + coordinate_3d& operator =(const coordinate_3d& other) + { + x = other.x; + y = other.y; + z = other.z; + + return *this; + } + + //*********************************** + coordinate_3d& operator +=(const coordinate_3d& rhs) + { + x += rhs.x; + y += rhs.y; + z += rhs.z; + + return *this; + } + + //*********************************** + coordinate_3d& operator -=(const coordinate_3d& rhs) + { + x -= rhs.x; + y -= rhs.y; + z -= rhs.z; + + return *this; + } + + TAxis x; + TAxis y; + TAxis z; + }; + + //*************************************************************************** + /// Equality operator for 2D coordinate. + //*************************************************************************** + template + bool operator ==(const coordinate_2d& lhs, const coordinate_2d& rhs) + { + return (lhs.x == rhs.x) && (lhs.y == rhs.y); + } + + //*************************************************************************** + /// Inequality operator for 2D coordinate. + //*************************************************************************** + template + bool operator !=(const coordinate_2d& lhs, const coordinate_2d& rhs) + { + return !(lhs == rhs); + } + + //*************************************************************************** + /// Addition operator for 2D coordinate. + //*************************************************************************** + template + coordinate_2d operator +(const coordinate_2d& lhs, const coordinate_2d& rhs) + { + return coordinate_2d(lhs.x + rhs.x, lhs.y + rhs.y); + } + + //*************************************************************************** + /// Subtraction operator for 2D coordinate. + //*************************************************************************** + template + coordinate_2d operator -(const coordinate_2d& lhs, const coordinate_2d& rhs) + { + return coordinate_2d(lhs.x - rhs.x, lhs.y - rhs.y); + } + + //*************************************************************************** + /// Equality operator for 3D coordinate. + //*************************************************************************** + template + bool operator ==(const coordinate_3d& lhs, const coordinate_3d& rhs) + { + return (lhs.x == rhs.x) && (lhs.y == rhs.y) && (lhs.z == rhs.z); + } + + //*************************************************************************** + /// Inequality operator for 3D coordinate. + //*************************************************************************** + template + bool operator !=(const coordinate_3d& lhs, const coordinate_3d& rhs) + { + return !(lhs == rhs); + } + + //*************************************************************************** + /// Addition operator for 3D coordinate. + //*************************************************************************** + template + coordinate_3d operator +(const coordinate_3d& lhs, const coordinate_3d& rhs) + { + return coordinate_3d(lhs.x + rhs.x, lhs.y + rhs.y, lhs.z + rhs.z); + } + + //*************************************************************************** + /// Subtraction operator for 3D coordinate. + //*************************************************************************** + template + coordinate_3d operator -(const coordinate_3d& lhs, const coordinate_3d& rhs) + { + return coordinate_3d(lhs.x - rhs.x, lhs.y - rhs.y, lhs.z - rhs.z); + } + + //*************************************************************************** + /// Dot product for 2D coordinate. + //*************************************************************************** + template + TAxis dot(const etl::coordinate_2d& first, const etl::coordinate_2d& second) + { + return (first.x * second.x) + (first.y * second.y); + } + + //*************************************************************************** + /// Dot product for 3D coordinate. + //*************************************************************************** + template + TAxis dot(const etl::coordinate_3d& first, const etl::coordinate_3d& second) + { + return (first.x * second.x) + (first.y * second.y) + (first.z * second.z); + } + + //*************************************************************************** + /// Cross product for 2D coordinate. + //*************************************************************************** + template + TAxis cross(const etl::coordinate_2d& first, const etl::coordinate_2d& second) + { + return (first.x * second.y) - (first.y * second.x); + } + + //*************************************************************************** + /// Cross product for 3D coordinate. + //*************************************************************************** + template + etl::coordinate_3d cross(const etl::coordinate_3d& first, const etl::coordinate_3d& second) + { + return etl::coordinate_3d((first.y * second.z) - (first.z * second.y), + (first.z * second.x) - (first.x * second.z), + (first.x * second.y) - (first.y * second.x)); + } +} + +#endif + diff --git a/include/etl/utility.h b/include/etl/utility.h index c37e3204..0d826165 100644 --- a/include/etl/utility.h +++ b/include/etl/utility.h @@ -33,6 +33,7 @@ SOFTWARE. #include "platform.h" #include "type_traits.h" +#include "coordinate.h" #if defined(ETL_IN_UNIT_TEST) || ETL_USING_STL #if ETL_CPP11_SUPPORTED @@ -331,39 +332,6 @@ namespace etl { return t; } - - //****************************************************************************** - /// 2D coordinate type. - template - struct coordinate_2d - { - typedef T value_type; - - coordinate_2d() - : x(T(0)) - , y(T(0)) - { - } - - coordinate_2d(T x_, T y_) - : x(x_) - , y(y_) - { - } - - friend bool operator ==(const coordinate_2d& lhs, const coordinate_2d& rhs) - { - return (lhs.x == rhs.x) && (lhs.y == rhs.y); - } - - friend bool operator !=(const coordinate_2d& lhs, const coordinate_2d& rhs) - { - return !(lhs == rhs); - } - - T x; - T y; - }; } #endif diff --git a/test/test_atomic_std.cpp b/test/test_atomic_std.cpp index 1bae0c1c..302e8825 100644 --- a/test/test_atomic_std.cpp +++ b/test/test_atomic_std.cpp @@ -502,14 +502,14 @@ namespace #endif etl::atomic_int32_t atomic_value = 0U; - etl::atomic start = false; + etl::atomic start = 0; void thread1() { RAISE_THREAD_PRIORITY; FIX_PROCESSOR_AFFINITY1; - while (!start.load()); + while (start.load() == 0); for (int i = 0; i < 10000000; ++i) { @@ -522,7 +522,7 @@ namespace RAISE_THREAD_PRIORITY; FIX_PROCESSOR_AFFINITY2; - while (!start.load()); + while (start.load() == 0); for (int i = 0; i < 10000000; ++i) { @@ -535,7 +535,7 @@ namespace std::thread t1(thread1); std::thread t2(thread2); - start.store(true); + start.store(1); t1.join(); t2.join(); diff --git a/test/test_center_of_gravity_1d.cpp b/test/test_center_of_gravity_1d.cpp new file mode 100644 index 00000000..30cd4e2b --- /dev/null +++ b/test/test_center_of_gravity_1d.cpp @@ -0,0 +1,111 @@ +///****************************************************************************** +//The MIT License(MIT) +// +//Embedded Template Library. +//https://github.com/ETLCPP/etl +//https://www.etlcpp.com +// +//Copyright(c) 2021 jwellbelove +// +//Permission is hereby granted, free of charge, to any person obtaining a copy +//of this software and associated documentation files(the "Software"), to deal +//in the Software without restriction, including without limitation the rights +//to use, copy, modify, merge, publish, distribute, sublicense, and / or sell +//copies of the Software, and to permit persons to whom the Software is +//furnished to do so, subject to the following conditions : +// +//The above copyright notice and this permission notice shall be included in all +//copies or substantial portions of the Software. +// +//THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +//IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +//FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE +//AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +//LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +//OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +//SOFTWARE. +//******************************************************************************/ + +#include "unit_test_framework.h" + +#include "etl/center_of_gravity_1d.h" +#include "etl/utility.h" +#include "etl/scaled_rounding.h" +#include "etl/utility.h" + +#include + +namespace +{ + using Cog = etl::center_of_gravity_1d; + + //*********************************** + using Pixel = etl::pair; + + //*********************************** + std::vector pixels = + { + { 31, 1 }, { 40, 1 }, { 31, 1 }, { 40, 1 }, + { 21, 2 }, { 21, 2 }, { 50, 2 }, { 50, 2 }, + }; + + SUITE(test_center_of_gravity_1d) + { + //************************************************************************* + TEST(test_default_constructor) + { + Cog cog; + + CHECK_EQUAL(0, cog.get()); + CHECK_EQUAL(0.0, cog.get()); + } + + //************************************************************************* + TEST(test_all_same_coordinates) + { + Cog cog; + + for (int i = 0; i < 10; ++i) + { + cog(1, 2); + } + + CHECK_EQUAL(1, cog.get()); + CHECK_EQUAL(1.0, cog.get()); + } + + //************************************************************************* + TEST(test_vector_of_coordinates) + { + Cog cog; + using coordi = etl::pair; + using coordd = etl::pair; + + for (const auto& pixel : pixels) + { + cog(pixel.first, pixel.second); + } + + CHECK_EQUAL(35, cog.get()); + CHECK_EQUAL(35.5, cog.get()); + } + + //************************************************************************* + TEST(test_vector_of_coordinates_with_round_half_up) + { + Cog cog; + using coord = etl::coordinate_2d; + + for (const auto& pixel : pixels) + { + cog(pixel.first, pixel.second); + } + + constexpr int Scale = 10; + + auto rounding = &etl::round_half_up_scaled; + + CHECK_EQUAL(36, (cog.get(rounding))); + } + }; +} diff --git a/test/test_center_of_gravity.cpp b/test/test_center_of_gravity_2d.cpp similarity index 84% rename from test/test_center_of_gravity.cpp rename to test/test_center_of_gravity_2d.cpp index 22532495..5bc15f5a 100644 --- a/test/test_center_of_gravity.cpp +++ b/test/test_center_of_gravity_2d.cpp @@ -28,7 +28,7 @@ #include "unit_test_framework.h" -#include "etl/center_of_gravity.h" +#include "etl/center_of_gravity_2d.h" #include "etl/utility.h" #include "etl/scaled_rounding.h" @@ -36,35 +36,19 @@ namespace { - using Cog = etl::center_of_gravity; + using Cog = etl::center_of_gravity_2d; //*********************************** - struct Point - { - int x; - int y; - uint8_t value; - }; + using Pixel = etl::coordinate_2d; //*********************************** - std::vector points = + std::vector pixels = { { 31, 21, 1 }, { 40, 21, 1 }, { 31, 30, 1 }, { 40, 30, 1 }, { 21, 11, 2 }, { 21, 40, 2 }, { 50, 11, 2 }, { 50, 40, 2 }, }; - //*********************************** - struct Proxy - { - void operator()(Point point) - { - cog(point.x, point.y, point.value); - } - - Cog& cog; - }; - - SUITE(test_center_of_gravity) + SUITE(test_center_of_gravity_2d) { //************************************************************************* TEST(test_default_constructor) @@ -103,13 +87,12 @@ namespace TEST(test_vector_of_coordinates) { Cog cog; - Proxy proxy{ cog }; using coordi = etl::coordinate_2d; using coordd = etl::coordinate_2d; - for (const auto& point : points) + for (const auto& pixel : pixels) { - proxy(point); + cog(pixel); } CHECK_EQUAL(35, cog.get_x()); @@ -126,21 +109,20 @@ namespace TEST(test_vector_of_coordinates_with_round_half_up) { Cog cog; - Proxy proxy{ cog }; using coord = etl::coordinate_2d; - for (const auto& point : points) + for (const auto& pixel : pixels) { - proxy(point); + cog(pixel); } constexpr int Scale = 10; - int(*rounding)(int) = &etl::round_half_up_scaled; + auto rounding = &etl::round_half_up_scaled; CHECK_EQUAL(36, (cog.get_x(rounding))); CHECK_EQUAL(26, (cog.get_y(rounding))); - CHECK((coord(36, 26)) == (cog.get(rounding))); + CHECK((coord(36, 26)) == (cog.get(rounding))); } }; } diff --git a/test/test_center_of_gravity_3d.cpp b/test/test_center_of_gravity_3d.cpp new file mode 100644 index 00000000..5c1512a0 --- /dev/null +++ b/test/test_center_of_gravity_3d.cpp @@ -0,0 +1,136 @@ +///****************************************************************************** +//The MIT License(MIT) +// +//Embedded Template Library. +//https://github.com/ETLCPP/etl +//https://www.etlcpp.com +// +//Copyright(c) 2021 jwellbelove +// +//Permission is hereby granted, free of charge, to any person obtaining a copy +//of this software and associated documentation files(the "Software"), to deal +//in the Software without restriction, including without limitation the rights +//to use, copy, modify, merge, publish, distribute, sublicense, and / or sell +//copies of the Software, and to permit persons to whom the Software is +//furnished to do so, subject to the following conditions : +// +//The above copyright notice and this permission notice shall be included in all +//copies or substantial portions of the Software. +// +//THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +//IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +//FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE +//AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +//LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +//OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +//SOFTWARE. +//******************************************************************************/ + +#include "unit_test_framework.h" + +#include "etl/center_of_gravity_3d.h" +#include "etl/utility.h" +#include "etl/scaled_rounding.h" + +#include +#include + +namespace +{ + using Cog = etl::center_of_gravity_3d; + + //*********************************** + using Pixel = etl::coordinate_3d; + + //*********************************** + std::vector pixels = + { + { 31, 21, 11, 1 }, { 40, 21, 11, 1 }, { 31, 30, 11, 1 }, { 40, 30, 11, 1 }, + { 21, 11, 11, 2 }, { 21, 40, 11, 2 }, { 50, 11, 11, 2 }, { 50, 40, 11, 2 }, + { 31, 21, 30, 1 }, { 40, 21, 30, 1 }, { 31, 30, 30, 1 }, { 40, 30, 30, 1 }, + { 21, 11, 30, 2 }, { 21, 40, 30, 2 }, { 50, 11, 30, 2 }, { 50, 40, 30, 2 }, + }; + + SUITE(test_center_of_gravity_3d) + { + //************************************************************************* + TEST(test_default_constructor) + { + Cog cog; + + CHECK_EQUAL(0, cog.get_x()); + CHECK_EQUAL(0, cog.get_y()); + CHECK_EQUAL(0, cog.get_z()); + CHECK_EQUAL(0.0, cog.get_x()); + CHECK_EQUAL(0.0, cog.get_y()); + CHECK_EQUAL(0.0, cog.get_z()); + + CHECK((std::tuple(0, 0, 0)) == (cog.get, int>())); + CHECK((etl::coordinate_3d(0, 0, 0)) == (cog.get>())); + } + + //************************************************************************* + TEST(test_all_same_coordinates) + { + Cog cog; + + for (int i = 0; i < 10; ++i) + { + cog(1, 2, 3, 4); + } + + CHECK_EQUAL(1, cog.get_x()); + CHECK_EQUAL(2, cog.get_y()); + CHECK_EQUAL(1.0, cog.get_x()); + CHECK_EQUAL(2.0, cog.get_y()); + CHECK((std::tuple(1, 2, 3)) == (cog.get, int>())); + CHECK((std::tuple(1.0, 2.0, 3.0)) == (cog.get, double>())); + CHECK((etl::coordinate_3d(1, 2, 3)) == (cog.get>())); + CHECK((etl::coordinate_3d(1, 2, 3)) == (cog.get>())); + } + + //************************************************************************* + TEST(test_vector_of_coordinates) + { + Cog cog; + using coordi = etl::coordinate_3d; + using coordd = etl::coordinate_3d; + + for (const auto& pixel : pixels) + { + cog(pixel); + } + + CHECK_EQUAL(35, cog.get_x()); + CHECK_EQUAL(25, cog.get_y()); + CHECK_EQUAL(20, cog.get_z()); + + CHECK_EQUAL(35.5, cog.get_x()); + CHECK_EQUAL(25.5, cog.get_y()); + CHECK_EQUAL(20.5, cog.get_z()); + + CHECK((coordi(35, 25, 20)) == (cog.get())); + CHECK((coordd(35.5, 25.5, 20.5)) == (cog.get())); + } + + //************************************************************************* + TEST(test_vector_of_coordinates_with_round_half_up) + { + Cog cog; + using coord = etl::coordinate_3d; + + for (const auto& pixel : pixels) + { + cog(pixel); + } + + constexpr int Scale = 10; + + auto rounding = &etl::round_half_up_scaled; + + CHECK_EQUAL(36, (cog.get_x(rounding))); + CHECK_EQUAL(26, (cog.get_y(rounding))); + CHECK((coord(36, 26, 26)) == (cog.get(rounding))); + } + }; +} diff --git a/test/test_coordinate.cpp b/test/test_coordinate.cpp new file mode 100644 index 00000000..b452f5ef --- /dev/null +++ b/test/test_coordinate.cpp @@ -0,0 +1,329 @@ +/****************************************************************************** +The MIT License(MIT) + +Embedded Template Library. +https://github.com/ETLCPP/etl +https://www.etlcpp.com + +Copyright(c) 2021 jwellbelove + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files(the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and / or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions : + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. +******************************************************************************/ + +#include "unit_test_framework.h" + +#include "etl/coordinate.h" + +#include + +namespace +{ + using Coord_2d = etl::coordinate_2d; + using Coord_v_2d = etl::coordinate_2d; + + using Coord_3d = etl::coordinate_3d; + using Coord_v_3d = etl::coordinate_3d; + + SUITE(test_coordinate) + { + //************************************************************************* + TEST(test_coordinate_2d_default_constructor) + { + Coord_2d coord; + Coord_v_2d coord_v; + + CHECK_EQUAL(0, coord.x); + CHECK_EQUAL(0, coord.y); + + CHECK_EQUAL(0, coord_v.x); + CHECK_EQUAL(0, coord_v.y); + CHECK_EQUAL(0, coord_v.value); + } + + //************************************************************************* + TEST(test_coordinate_2d_constructor) + { + Coord_2d coord(1, 2); + Coord_v_2d coord_v(1, 2, 3); + + CHECK_EQUAL(1, coord.x); + CHECK_EQUAL(2, coord.y); + + CHECK_EQUAL(1, coord_v.x); + CHECK_EQUAL(2, coord_v.y); + CHECK_EQUAL(3, coord_v.value); + } + + //************************************************************************* + TEST(test_coordinate_2d_copy_constructor) + { + Coord_2d input(1, 2); + Coord_2d coord(input); + Coord_v_2d input_v(1, 2, 3); + Coord_v_2d coord_v(input_v); + + CHECK_EQUAL(1, coord.x); + CHECK_EQUAL(2, coord.y); + + CHECK_EQUAL(1, coord_v.x); + CHECK_EQUAL(2, coord_v.y); + CHECK_EQUAL(3, coord_v.value); + } + + //************************************************************************* + TEST(test_coordinate_2d_assignment) + { + Coord_2d input(1, 2); + Coord_2d coord; + Coord_v_2d input_v(1, 2, 3); + Coord_v_2d coord_v; + + coord = input; + coord_v = input_v; + + CHECK_EQUAL(1, coord.x); + CHECK_EQUAL(2, coord.y); + + CHECK_EQUAL(1, coord_v.x); + CHECK_EQUAL(2, coord_v.y); + CHECK_EQUAL(3, coord_v.value); + } + + //************************************************************************* + TEST(test_coordinate_2d_addition) + { + Coord_2d input1(1, 2); + Coord_2d input2(3, 4); + Coord_2d coord; + Coord_2d result(4, 6); + + Coord_v_2d input1_v(1, 2, 3); + Coord_v_2d input2_v(4, 5, 6); + Coord_v_2d coord_v; + Coord_v_2d result_v(5, 7); + + coord = input1 + input2; + coord_v = input1_v + input2_v; + + CHECK(coord == result); + CHECK(coord_v == result_v); + + coord = input1; + coord_v = input1_v; + + coord += input2; + coord_v += input2_v; + + CHECK(coord == result); + CHECK(coord_v == result_v); + } + + //************************************************************************* + TEST(test_coordinate_2d_subtraction) + { + Coord_2d input1(1, 2); + Coord_2d input2(3, 4); + Coord_2d coord; + Coord_2d result(-2, -2); + + Coord_v_2d input1_v(1, 2, 3); + Coord_v_2d input2_v(4, 5, 6); + Coord_v_2d coord_v; + Coord_v_2d result_v(-3, -3); + + coord = input1 - input2; + coord_v = input1_v - input2_v; + + CHECK(coord == result); + CHECK(coord_v == result_v); + + coord = input1; + coord_v = input1_v; + + coord -= input2; + coord_v -= input2_v; + + CHECK(coord == result); + CHECK(coord_v == result_v); + } + + //************************************************************************* + TEST(test_coordinate_2d_) + { + Coord_2d input1(1, 2); + Coord_2d input2(3, 4); + Coord_2d coord(input1); + Coord_v_2d input1_v(1, 2, 3); + Coord_v_2d input2_v(4, 5, 6); + Coord_v_2d coord_v(input1_v); + + CHECK(coord == input1); + CHECK(coord_v == input1_v); + + CHECK(coord != input2); + CHECK(coord_v != input2_v); + } + + //************************************************************************* + TEST(test_coordinate_3d_default_constructor) + { + Coord_3d coord; + Coord_v_3d coord_v; + + CHECK_EQUAL(0, coord.x); + CHECK_EQUAL(0, coord.y); + CHECK_EQUAL(0, coord.z); + + CHECK_EQUAL(0, coord_v.x); + CHECK_EQUAL(0, coord_v.y); + CHECK_EQUAL(0, coord_v.z); + CHECK_EQUAL(0, coord_v.value); + } + + //************************************************************************* + TEST(test_coordinate_3d_constructor) + { + Coord_3d coord(1, 2, 3); + Coord_v_3d coord_v(1, 2, 3, 4); + + CHECK_EQUAL(1, coord.x); + CHECK_EQUAL(2, coord.y); + CHECK_EQUAL(3, coord.z); + + CHECK_EQUAL(1, coord_v.x); + CHECK_EQUAL(2, coord_v.y); + CHECK_EQUAL(3, coord_v.z); + CHECK_EQUAL(4, coord_v.value); + } + + //************************************************************************* + TEST(test_coordinate_3d_copy_constructor) + { + Coord_3d input(1, 2, 3); + Coord_3d coord(input); + Coord_v_3d input_v(1, 2, 3, 4); + Coord_v_3d coord_v(input_v); + + CHECK_EQUAL(1, coord.x); + CHECK_EQUAL(2, coord.y); + CHECK_EQUAL(3, coord.z); + + CHECK_EQUAL(1, coord_v.x); + CHECK_EQUAL(2, coord_v.y); + CHECK_EQUAL(3, coord_v.z); + CHECK_EQUAL(4, coord_v.value); + } + + //************************************************************************* + TEST(test_coordinate_3d_assignment) + { + Coord_3d input(1, 2, 3); + Coord_3d coord; + Coord_v_3d input_v(1, 2, 3, 4); + Coord_v_3d coord_v; + + coord = input; + coord_v = input_v; + + CHECK_EQUAL(1, coord.x); + CHECK_EQUAL(2, coord.y); + CHECK_EQUAL(3, coord.z); + + CHECK_EQUAL(1, coord_v.x); + CHECK_EQUAL(2, coord_v.y); + CHECK_EQUAL(3, coord_v.z); + CHECK_EQUAL(4, coord_v.value); + } + + //************************************************************************* + TEST(test_coordinate_3d_equality) + { + Coord_3d input1(1, 2, 3); + Coord_3d input2(4, 5, 6); + Coord_3d coord(input1); + Coord_v_3d input1_v(1, 2, 3, 4); + Coord_v_3d input2_v(5, 6, 7, 8); + Coord_v_3d coord_v(input1_v); + + CHECK(coord == input1); + CHECK(coord_v == input1_v); + + CHECK(coord != input2); + CHECK(coord_v != input2_v); + } + + //************************************************************************* + TEST(test_coordinate_3d_addition) + { + Coord_3d input1(1, 2, 3); + Coord_3d input2(4, 5, 6); + Coord_3d coord; + Coord_3d result(5, 7, 9); + + Coord_v_3d input1_v(1, 2, 3, 4); + Coord_v_3d input2_v(5, 6, 7, 8); + Coord_v_3d coord_v; + Coord_v_3d result_v(6, 8, 10, 12); + + coord = input1 + input2; + coord_v = input1_v + input2_v; + + CHECK(coord == result); + CHECK(coord_v == result_v); + + coord = input1; + coord_v = input1_v; + + coord += input2; + coord_v += input2_v; + + CHECK(coord == result); + CHECK(coord_v == result_v); + } + + //************************************************************************* + TEST(test_coordinate_3d_subtraction) + { + Coord_3d input1(1, 2, 3); + Coord_3d input2(4, 5, 6); + Coord_3d coord; + Coord_3d result(-3, -3, -3); + + Coord_v_3d input1_v(1, 2, 3, 4); + Coord_v_3d input2_v(5, 6, 7, 8); + Coord_v_3d coord_v; + Coord_v_3d result_v(-4, -4, -4, -4); + + coord = input1 - input2; + coord_v = input1_v - input2_v; + + CHECK(coord == result); + CHECK(coord_v == result_v); + + coord = input1; + coord_v = input1_v; + + coord -= input2; + coord_v -= input2_v; + + CHECK(coord == result); + CHECK(coord_v == result_v); + } + }; +} diff --git a/test/vs2019/etl.vcxproj b/test/vs2019/etl.vcxproj index 23a9e933..93f8cd2e 100644 --- a/test/vs2019/etl.vcxproj +++ b/test/vs2019/etl.vcxproj @@ -1255,11 +1255,14 @@ - + + + + @@ -4428,10 +4431,13 @@ - + + + + diff --git a/test/vs2019/etl.vcxproj.filters b/test/vs2019/etl.vcxproj.filters index dde98b11..38973cbd 100644 --- a/test/vs2019/etl.vcxproj.filters +++ b/test/vs2019/etl.vcxproj.filters @@ -1113,7 +1113,16 @@ ETL\Patterns - + + ETL\Graphical + + + ETL\Graphical + + + ETL\Graphical + + ETL\Graphical @@ -2543,7 +2552,16 @@ Source Files - + + Source Files + + + Source Files + + + Source Files + + Source Files From deba2c0fd936dbc5e3b79eaf1479e1a8e4b66d0c Mon Sep 17 00:00:00 2001 From: John Wellbelove Date: Wed, 24 Aug 2022 14:02:21 +0100 Subject: [PATCH 18/18] Updated project files --- test/vs2019/etl.vcxproj | 10 +++++++ test/vs2019/etl.vcxproj.filters | 51 +++++++++++++++++++++++++++------ 2 files changed, 52 insertions(+), 9 deletions(-) diff --git a/test/vs2019/etl.vcxproj b/test/vs2019/etl.vcxproj index ba2640b6..0a6fd23d 100644 --- a/test/vs2019/etl.vcxproj +++ b/test/vs2019/etl.vcxproj @@ -2379,6 +2379,7 @@ + @@ -2386,10 +2387,14 @@ + + + + @@ -11260,6 +11265,7 @@ + @@ -11267,10 +11273,14 @@ + + + + diff --git a/test/vs2019/etl.vcxproj.filters b/test/vs2019/etl.vcxproj.filters index ee3af104..1e6bafb2 100644 --- a/test/vs2019/etl.vcxproj.filters +++ b/test/vs2019/etl.vcxproj.filters @@ -65,9 +65,6 @@ {c25471f3-451a-4279-925d-cbdcec912ef8} - - {586d2c92-e504-4dea-9b1f-42d725a5272c} - {74399f00-a7a3-47e3-9b27-d01fb2b5ce87} @@ -217,6 +214,12 @@ {de372ec9-d193-4956-871f-065414a9d3be} + + {15d9b18f-bc5e-42bf-82b1-7cceee7aac38} + + + {2d8a82e2-31ae-4799-9758-6699893bb3f5} + @@ -780,9 +783,6 @@ ETL\Strings - - ETL\Pseudo Containers - ETL\Strings @@ -1332,6 +1332,24 @@ ETL\Containers + + ETL\Graphical + + + ETL\Graphical + + + ETL\Graphical + + + ETL\Graphical + + + ETL\Graphical + + + ETL\Graphical + @@ -1961,9 +1979,6 @@ Tests\Types - - Tests\Algorithms - Tests\Types @@ -3353,6 +3368,24 @@ Tests\Binary + + Tests\Graphical + + + Tests\Graphical + + + Tests\Graphical + + + Tests\Graphical + + + Tests\Graphical + + + Tests\Graphical +