VideoTools
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Pages
grlinedraw.h
Go to the documentation of this file.
1 //
2 // Copyright (C) 2017 Graeme Walker
3 //
4 // This program is free software: you can redistribute it and/or modify
5 // it under the terms of the GNU General Public License as published by
6 // the Free Software Foundation, either version 3 of the License, or
7 // (at your option) any later version.
8 //
9 // This program is distributed in the hope that it will be useful,
10 // but WITHOUT ANY WARRANTY; without even the implied warranty of
11 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 // GNU General Public License for more details.
13 //
14 // You should have received a copy of the GNU General Public License
15 // along with this program. If not, see <http://www.gnu.org/licenses/>.
16 // ===
17 ///
18 /// \file grlinedraw.h
19 ///
20 
21 #ifndef GR_LINE_DRAW__H
22 #define GR_LINE_DRAW__H
23 
24 #include "gdef.h"
25 #include <utility> // std::pair<>
26 
27 namespace Gr
28 {
29  template <typename T> class LineDrawImp ;
30  template <typename T> class LineDraw ;
31 }
32 
33 /// \class Gr::LineDrawImp
34 /// A low-level line-drawing class used in the implementation
35 /// of Gr::LineDraw.
36 ///
37 /// The client code iterates over the points in the longest of
38 /// the two dimensions, without having to know which dimension
39 /// is the longest or which direction they are going.
40 ///
41 /// Usage:
42 /// \code
43 /// Gr::LineDrawImp<int> line( x1 , y1 , x2 , y2 ) ;
44 /// plot( line.x() , line.y() ) ;
45 /// for( int i = 0 ; i < line.n() ; i++ )
46 /// {
47 /// line.nextPoint() ;
48 /// plot( line.x() , line.y() ) ;
49 /// }
50 /// \endcode
51 ///
52 template <typename T>
53 class Gr::LineDrawImp
54 {
55 public:
56  LineDrawImp( T x1 , T y1 , T x2 , T y2 ) ;
57  ///< Constructor.
58 
59  T n() const ;
60  ///< Returns the iteration count.
61 
62  bool nextPoint() ;
63  ///< Steps to the next point for point-wise iteration.
64  ///< Returns false if (x(),y()) is now off the end.
65 
66  T x() const ;
67  ///< Returns the current x coordinate for point-wise iteration.
68 
69  T y() const ;
70  ///< Returns the current y coordinate for point-wise iteration.
71 
72  bool flat() const ;
73  ///< Returns true if the x dimension of the
74  ///< line is greater the the y dimension.
75 
76 private:
77  bool m_flat ;
78  T m_dx ;
79  T m_dy ;
80  T m_big ;
81  T m_small ;
82  T m_dbig ;
83  T m_dsmall ;
84  T m_step_big ;
85  T m_step_small ;
86  T m_brmax ;
87  T m_brc ;
88  T m_big_off_end ;
89 } ;
90 
91 
92 /// \class Gr::LineDraw
93 /// A class template for drawing lines in terms of separate horizontal line
94 /// segments.
95 /// Usage:
96 /// \code
97 /// LineDraw<int> line_scan( ... ) ;
98 /// while( line_scan.more() )
99 /// drawSegment( line_scan.x1() , line_scan.x2() , line_scan.y() ) ;
100 /// \endcode
101 ///
102 template <typename T>
103 class Gr::LineDraw
104 {
105 public:
106  LineDraw( T x1 , T y1 , T x2 , T y2 ) ;
107  ///< Constructor.
108 
109  bool more() ;
110  ///< Iterator for the next line segment. Returns true at least once.
111 
112  T x1() const ;
113  ///< Returns the current smaller x coordinate.
114 
115  T x2() const ;
116  ///< Returns the current larger x coordinate.
117 
118  T y() const ;
119  ///< Returns the current y coordinate.
120 
121  bool flat() const ;
122  ///< Returns true if the x dimension of the
123  ///< line is greater the the y dimension.
124 
125 private:
126  void assign() ;
127  void iterate() ;
128 
129 private:
130  LineDrawImp<T> m_line ;
131  T m_x1 ;
132  T m_x2 ;
133  T m_y ;
134  bool m_horizontal ;
135  bool m_first ;
136  bool m_off_end ;
137 } ;
138 
139 
140 template <typename T>
141 Gr::LineDrawImp<T>::LineDrawImp( T x1 , T y1 , T x2 , T y2 )
142 {
143  m_dx = (x2 > x1) ? (x2 - x1) : (x1 - x2) ;
144  m_dy = (y2 > y1) ? (y2 - y1) : (y1 - y2) ;
145  m_flat = m_dx > m_dy ;
146  m_big = m_flat ? x1 : y1 ;
147  m_small = m_flat ? y1 : x1 ;
148  m_step_big = m_flat ? ( x2 < x1 ? -1 : 1 ) : ( y2 < y1 ? -1 : 1 ) ;
149  m_step_small = m_flat ? ( y2 < y1 ? -1 : 1 ) : ( x2 < x1 ? -1 : 1 ) ;
150  m_dbig = m_flat ? m_dx : m_dy ;
151  m_dsmall = m_flat ? m_dy : m_dx ;
152  m_brmax = m_dbig ;
153  m_brc = m_dbig / T(2) ;
154  m_big_off_end = (m_flat ? x2 : y2) + m_step_big ;
155 }
156 
157 template <typename T>
159 {
160  return m_flat ? m_big : m_small ;
161 }
162 
163 template <typename T>
165 {
166  return m_flat ? m_small : m_big ;
167 }
168 
169 template <typename T>
171 {
172  return m_dbig ;
173 }
174 
175 template <typename T>
177 {
178  if( m_big != m_big_off_end )
179  {
180  m_big += m_step_big ;
181  m_brc += m_dsmall ;
182  if( m_brc > m_brmax )
183  {
184  m_brc -= m_dbig ;
185  m_small += m_step_small ;
186  }
187  }
188  return m_big != m_big_off_end ;
189 }
190 
191 template <typename T>
193 {
194  return m_flat ;
195 }
196 
197 
198 template <typename T>
199 Gr::LineDraw<T>::LineDraw( T x1 , T y1 , T x2 , T y2 ) :
200  m_line( x1 , y1 , x2 , y2 ) ,
201  m_x1( x1 ) ,
202  m_x2( x2 ) ,
203  m_y( y1 ) ,
204  m_horizontal( y1 == y2 ) ,
205  m_first( true ) ,
206  m_off_end( false )
207 {
208 }
209 
210 template <typename T>
212 {
213  m_x1 = m_x2 = m_line.x() ;
214  m_y = m_line.y() ;
215 }
216 
217 template <typename T>
219 {
220  // walk along the line's larger dimension until the y value
221  // changes; set x2 as the x value just prior to that point
222  bool ok = true ;
223  do
224  {
225  m_x2 = m_line.x() ;
226  ok = m_line.nextPoint() ;
227  } while( ok && m_line.y() == m_y ) ;
228  m_off_end = !ok ;
229 }
230 
231 template <typename T>
233 {
234  if( m_first )
235  {
236  m_first = false ;
237  if( m_horizontal )
238  {
239  ; // no-op -- set up in ctor
240  }
241  else if( m_line.flat() )
242  {
243  assign() ;
244  iterate() ;
245  }
246  else
247  {
248  assign() ;
249  }
250  return true ;
251  }
252  else if( m_horizontal )
253  {
254  return false ;
255  }
256  else if( m_line.flat() && m_off_end )
257  {
258  return false ;
259  }
260  else if( m_line.flat() )
261  {
262  assign() ;
263  iterate() ;
264  return true ;
265  }
266  else
267  {
268  bool rc = m_line.nextPoint() ;
269  assign() ;
270  return rc ;
271  }
272 }
273 
274 template <typename T>
276 {
277  return m_line.flat() ;
278 }
279 
280 template <typename T>
282 {
283  return m_x1 < m_x2 ? m_x1 : m_x2 ;
284 }
285 
286 template <typename T>
288 {
289  return m_x1 < m_x2 ? m_x2 : m_x1 ;
290 }
291 
292 template <typename T>
294 {
295  return m_y ;
296 }
297 
298 #endif
T y() const
Returns the current y coordinate.
Definition: grlinedraw.h:293
A class template for drawing lines in terms of separate horizontal line segments. ...
Definition: grlinedraw.h:30
bool flat() const
Returns true if the x dimension of the line is greater the the y dimension.
Definition: grlinedraw.h:192
T x1() const
Returns the current smaller x coordinate.
Definition: grlinedraw.h:281
T y() const
Returns the current y coordinate for point-wise iteration.
Definition: grlinedraw.h:164
T n() const
Returns the iteration count.
Definition: grlinedraw.h:170
T x() const
Returns the current x coordinate for point-wise iteration.
Definition: grlinedraw.h:158
A low-level line-drawing class used in the implementation of Gr::LineDraw.
Definition: grlinedraw.h:29
LineDrawImp(T x1, T y1, T x2, T y2)
Constructor.
Definition: grlinedraw.h:141
bool flat() const
Returns true if the x dimension of the line is greater the the y dimension.
Definition: grlinedraw.h:275
T x2() const
Returns the current larger x coordinate.
Definition: grlinedraw.h:287
bool more()
Iterator for the next line segment. Returns true at least once.
Definition: grlinedraw.h:232
bool nextPoint()
Steps to the next point for point-wise iteration.
Definition: grlinedraw.h:176
LineDraw(T x1, T y1, T x2, T y2)
Constructor.
Definition: grlinedraw.h:199