diff --git a/include/etl/bresenham.h b/include/etl/bresenham_line.h similarity index 74% rename from include/etl/bresenham.h rename to include/etl/bresenham_line.h index 21a76992..7576ff2b 100644 --- a/include/etl/bresenham.h +++ b/include/etl/bresenham_line.h @@ -42,6 +42,8 @@ namespace etl //*************************************************************************** /// A pseudo-container that generates points on a line, using Bresenham's /// line algorithm. + /// TPoint must support integral x & y members. + /// TIntegral is the internal working variable type. Default is int. //*************************************************************************** template class bresenham_line @@ -54,14 +56,12 @@ namespace etl typedef TPoint value_type; typedef size_t size_type; typedef ptrdiff_t difference_type; - typedef value_type& reference; + typedef value_type& reference; typedef const value_type& const_reference; - typedef value_type* pointer; + typedef value_type* pointer; typedef const value_type* const_pointer; - friend class const_iterator; - - class const_iterator : public etl::iterator + class iterator : public etl::iterator { public: @@ -70,7 +70,7 @@ namespace etl //*************************************************** /// //*************************************************** - const_iterator() + iterator() : p_bresenham_line(ETL_NULLPTR) { } @@ -78,7 +78,7 @@ namespace etl //*************************************************** /// //*************************************************** - const_iterator(const const_iterator& other) + iterator(const iterator& other) : p_bresenham_line(other.p_bresenham_line) { } @@ -86,7 +86,7 @@ namespace etl //*************************************************** /// //*************************************************** - const_iterator& operator =(const const_iterator& rhs) + iterator& operator =(const iterator& rhs) { p_bresenham_line = rhs.p_bresenham_line; } @@ -94,10 +94,10 @@ namespace etl //*************************************************** /// //*************************************************** - const_iterator& operator ++() + iterator& operator ++() { // Has the end of the series has been reached? - if (p_bresenham_line->count == 0) + if (p_bresenham_line->current_count == 0) { // Mark it as an end iterator. p_bresenham_line = ETL_NULLPTR; @@ -126,46 +126,62 @@ namespace etl return p_bresenham_line->get_point(); } + //*************************************************** + /// + //*************************************************** + friend bool operator ==(const iterator& lhs, const iterator& rhs) + { + return lhs.p_bresenham_line == rhs.p_bresenham_line; + } + + //*************************************************** + /// + //*************************************************** + friend bool operator !=(const iterator& lhs, const iterator& rhs) + { + return !(lhs == rhs); + } + private: //*************************************************** /// //*************************************************** - const_iterator(bresenham_line* pb) + iterator(bresenham_line* pb) : p_bresenham_line(pb) { } - bresenham_line* p_bresenham_line; + bresenham_line* p_bresenham_line; }; //*************************************************** /// Constructor. //*************************************************** - bresenham_line(const_reference start_, const_reference end_) - : start(start_) - , end(end_) - , current(start_) - , x_increment((end_.x < start_.x) ? -1 : 1) - , y_increment((end_.y < start_.y) ? -1 : 1) - , do_minor_increment(true) + bresenham_line(const_reference first_, const_reference last_) + : first(first_) + , last(last_) + , current(first_) + , x_increment((last_.x < first_.x) ? -1 : 1) + , y_increment((last_.y < first_.y) ? -1 : 1) + , do_minor_increment(false) { - dx = (end_.x < start_.x) ? start_.x - end_.x : end_.x - start_.x; - dy = (end_.y < start_.y) ? start_.y - end_.y : end_.y - start_.y; + 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; if (is_y_major_axis()) { total_count = dy; - dx *= 2; - balance = dx - dy; - dy *= 2; + dx *= 2; + balance = dx - dy; + dy *= 2; } else { total_count = dx; - dy *= 2; - balance = dy - dx; - dx *= 2; + dy *= 2; + balance = dy - dx; + dx *= 2; } current_count = total_count; @@ -174,39 +190,20 @@ namespace etl //*************************************************** /// //*************************************************** - const_iterator begin() const + iterator begin() { current_count = total_count; - current = start; + current = first; - return const_iterator(this); + return iterator(this); } //*************************************************** /// //*************************************************** - const_iterator cbegin() const + iterator end() const { - current_count = total_count; - current = start; - - return const_iterator(this); - } - - //*************************************************** - /// - //*************************************************** - const_iterator end() const - { - return const_iterator(); - } - - //*************************************************** - /// - //*************************************************** - const_iterator cend() const - { - return const_iterator(); + return iterator(); } //*************************************************** @@ -278,18 +275,19 @@ namespace etl return current; } - const value_type start; - const value_type end; - value_type current; - const TIntegral x_increment; - const TIntegral y_increment; - TIntegral dx; - TIntegral dy; - TIntegral total_count; - TIntegral current_count; - TIntegral balance; - bool do_minor_increment; + const value_type first; + const value_type last; + value_type current; + const TIntegral x_increment; + const TIntegral y_increment; + TIntegral dx; + TIntegral dy; + TIntegral total_count; + TIntegral current_count; + TIntegral balance; + bool do_minor_increment; }; +} #endif diff --git a/test/test_bresenham_line.cpp b/test/test_bresenham_line.cpp new file mode 100644 index 00000000..3de7f2b8 --- /dev/null +++ b/test/test_bresenham_line.cpp @@ -0,0 +1,346 @@ +/****************************************************************************** +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 "UnitTest++/UnitTest++.h" + +#include "etl/bresenham_line.h" + +#include + +namespace +{ + struct Point + { + int x; + int y; + }; + + bool operator ==(Point lhs, Point rhs) + { + return (lhs.x == rhs.x) && (lhs.y == rhs.y); + } + + std::ostream& operator << (std::ostream& os, Point point) + { + os << "(" << point.x << "," << point.y << ")"; + return os; + } + + using BresenhamLine = etl::bresenham_line; + + SUITE(test_bresenham_line) + { + //************************************************************************* + TEST(horizontal_line_left_right) + { + Point first = { -5, 5 }; + Point last = { 5, 5 }; + + BresenhamLine bl(first, last); + + BresenhamLine::iterator itr = bl.begin(); + + std::vector expected{ Point{-5, 5 }, Point{-4, 5 }, Point{-3, 5 }, Point{-2, 5 }, Point{-1, 5 }, Point{ 0, 5 }, + Point{ 1, 5 }, Point{ 2, 5 }, Point{ 3, 5 }, Point{ 4, 5 }, Point{ 5, 5} }; + std::vector actual; + + while (itr != bl.end()) + { + actual.push_back(*itr); + ++itr; + } + + 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 = { 5, 5 }; + Point last = { -5, 5 }; + + BresenhamLine bl(first, last); + + BresenhamLine::iterator itr = bl.begin(); + + std::vector expected{ Point{ 5, 5 }, Point{ 4, 5 }, Point{ 3, 5 }, Point{ 2, 5 }, Point{ 1, 5 }, Point{ 0, 5 }, + Point{-1, 5 }, Point{-2, 5 }, Point{-3, 5 }, Point{-4, 5 }, Point{-5, 5} }; + std::vector actual; + + while (itr != bl.end()) + { + actual.push_back(*itr); + ++itr; + } + + 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, -5 }; + Point last = { 5, 5 }; + + BresenhamLine bl(first, last); + + BresenhamLine::iterator itr = bl.begin(); + + std::vector expected{ Point{ 5, -5 }, Point{ 5, -4 }, Point{ 5, -3 }, Point{ 5, -2 }, Point{ 5, -1 }, Point{ 5, 0 }, + Point{ 5, 1 }, Point{ 5, 2 }, Point{ 5, 3 }, Point{ 5, 4 }, Point{ 5, 5} }; + std::vector actual; + + while (itr != bl.end()) + { + actual.push_back(*itr); + ++itr; + } + + 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, 5 }; + Point last = { 5, -5 }; + + BresenhamLine bl(first, last); + + BresenhamLine::iterator itr = bl.begin(); + + std::vector expected{ Point{ 5, 5 }, Point{ 5, 4 }, Point{ 5, 3 }, Point{ 5, 2 }, Point{ 5, 1 }, Point{ 5, 0 }, + Point{ 5, -1 }, Point{ 5, -2 }, Point{ 5, -3 }, Point{ 5, -4 }, Point{ 5, -5} }; + std::vector actual; + + while (itr != bl.end()) + { + actual.push_back(*itr); + ++itr; + } + + 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 = { -5, -3 }; + Point last = { 5, 3}; + + BresenhamLine bl(first, last); + + BresenhamLine::iterator itr = bl.begin(); + + std::vector expected{ Point{ -5, -3 }, Point{ -4, -3 }, Point{ -3, -2 }, Point{ -2, -1 }, Point{ -1, -1 }, Point{ 0, 0 }, + Point{ 1, 1 }, Point{ 2, 1 }, Point{ 3, 2 }, Point{ 4, 2 }, Point{ 5, 3 } }; + std::vector actual; + + while (itr != bl.end()) + { + actual.push_back(*itr); + ++itr; + } + + 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 = { 5, 3 }; + Point last = { -5, -3 }; + + BresenhamLine bl(first, last); + + BresenhamLine::iterator itr = bl.begin(); + + std::vector expected{ Point{ 5, 3 }, Point{ 4, 3 }, Point{ 3, 2 }, Point{ 2, 1 }, Point{ 1, 1 }, Point{ 0, 0 }, + Point{ -1, -1 }, Point{ -2, -1 }, Point{ -3, -2 }, Point{ -4, -2 }, Point{ -5, -3 } }; + std::vector actual; + + while (itr != bl.end()) + { + actual.push_back(*itr); + ++itr; + } + + 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 = { 5, -3 }; + Point last = { -5, 3 }; + + BresenhamLine bl(first, last); + + BresenhamLine::iterator itr = bl.begin(); + + std::vector expected{ Point{ 5, -3 }, Point{ 4, -3 }, Point{ 3, -2 }, Point{ 2, -1 }, Point{ 1, -1 }, Point{ 0, 0 }, + Point{ -1, 1 }, Point{ -2, 1 }, Point{ -3, 2 }, Point{ -4, 2 }, Point{ -5, 3 } }; + std::vector actual; + + while (itr != bl.end()) + { + actual.push_back(*itr); + ++itr; + } + + 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 = { -5, 3 }; + Point last = { 5, -3 }; + + BresenhamLine bl(first, last); + + BresenhamLine::iterator itr = bl.begin(); + + std::vector expected{ Point{ -5, 3 }, Point{ -4, 3 }, Point{ -3, 2 }, Point{ -2, 1 }, Point{ -1, 1 }, Point{ 0, 0 }, + Point{ 1, -1 }, Point{ 2, -1 }, Point{ 3, -2 }, Point{ 4, -2 }, Point{ 5, -3 } }; + std::vector actual; + + while (itr != bl.end()) + { + actual.push_back(*itr); + ++itr; + } + + 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 = { -3, -5 }; + Point last = { 3, 5 }; + + BresenhamLine bl(first, last); + + BresenhamLine::iterator itr = bl.begin(); + + std::vector expected{ Point{ -3, -5 }, Point{ -3, -4 }, Point{ -2, -3 }, Point{ -1, -2 }, Point{ -1, -1 }, Point{ 0, 0 }, + Point{ 1, 1 }, Point{ 1, 2 }, Point{ 2, 3 }, Point{ 2, 4 }, Point{ 3, 5 } }; + std::vector actual; + + while (itr != bl.end()) + { + actual.push_back(*itr); + ++itr; + } + + 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 = { 3, 5 }; + Point last = { -3, -5 }; + + BresenhamLine bl(first, last); + + BresenhamLine::iterator itr = bl.begin(); + + std::vector expected{ Point{ 3, 5 }, Point{ 3, 4 }, Point{ 2, 3 }, Point{ 1, 2 }, Point{ 1, 1 }, Point{ 0, 0 }, + Point{ -1, -1 }, Point{ -1, -2 }, Point{ -2, -3 }, Point{ -2, -4 }, Point{ -3, -5 } }; + std::vector actual; + + while (itr != bl.end()) + { + actual.push_back(*itr); + ++itr; + } + + 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 = { 3, -5 }; + Point last = { -3, 5 }; + + BresenhamLine bl(first, last); + + BresenhamLine::iterator itr = bl.begin(); + + std::vector expected{ Point{ 3, -5 }, Point{ 3, -4 }, Point{ 2, -3 }, Point{ 1, -2 }, Point{ 1, -1 }, Point{ 0, 0 }, + Point{ -1, 1 }, Point{ -1, 2 }, Point{ -2, 3 }, Point{ -2, 4 }, Point{ -3, 5 } }; + std::vector actual; + + while (itr != bl.end()) + { + actual.push_back(*itr); + ++itr; + } + + 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 = { -3, 5 }; + Point last = { 3, -5 }; + + BresenhamLine bl(first, last); + + BresenhamLine::iterator itr = bl.begin(); + + std::vector expected{ Point{ -3, 5 }, Point{ -3, 4 }, Point{ -2, 3 }, Point{ -1, 2 }, Point{ -1, 1 }, Point{ 0, 0 }, + Point{ 1, -1 }, Point{ 1, -2 }, Point{ 2, -3 }, Point{ 2, -4 }, Point{ 3, -5 } }; + std::vector actual; + + while (itr != bl.end()) + { + actual.push_back(*itr); + ++itr; + } + + CHECK_EQUAL(expected.size(), actual.size()); + CHECK_ARRAY_EQUAL(expected.data(), actual.data(), (std::max(expected.size(), actual.size()))); + } + }; +} diff --git a/test/vs2019/etl.vcxproj b/test/vs2019/etl.vcxproj index a1854ee9..505f4b3a 100644 --- a/test/vs2019/etl.vcxproj +++ b/test/vs2019/etl.vcxproj @@ -1015,7 +1015,7 @@ - + @@ -1266,6 +1266,7 @@ + diff --git a/test/vs2019/etl.vcxproj.filters b/test/vs2019/etl.vcxproj.filters index 18871841..cdaf4af2 100644 --- a/test/vs2019/etl.vcxproj.filters +++ b/test/vs2019/etl.vcxproj.filters @@ -879,7 +879,7 @@ ETL\Strings - + ETL\Pseudo Containers @@ -1394,6 +1394,9 @@ Source Files + + Source Files +