1 /**************************************************************
2  *
3  * Licensed to the Apache Software Foundation (ASF) under one
4  * or more contributor license agreements.  See the NOTICE file
5  * distributed with this work for additional information
6  * regarding copyright ownership.  The ASF licenses this file
7  * to you under the Apache License, Version 2.0 (the
8  * "License"); you may not use this file except in compliance
9  * with the License.  You may obtain a copy of the License at
10  *
11  *   http://www.apache.org/licenses/LICENSE-2.0
12  *
13  * Unless required by applicable law or agreed to in writing,
14  * software distributed under the License is distributed on an
15  * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16  * KIND, either express or implied.  See the License for the
17  * specific language governing permissions and limitations
18  * under the License.
19  *
20  *************************************************************/
21 
22 
23 
24 #ifndef INCLUDED_BASEBMP_LINERENDERER_HXX
25 #define INCLUDED_BASEBMP_LINERENDERER_HXX
26 
27 #include <basegfx/point/b2ipoint.hxx>
28 
29 #include <vigra/diff2d.hxx>
30 #include <vigra/iteratortraits.hxx>
31 
32 
33 /* Scan-converting lines */
34 
35 namespace basebmp
36 {
37 
38 /** Render line with Bresenham
39 
40     This function renders the line given by rPt1 and rPt2 using the
41     Bresenham algorithm with the specified color value. Make sure rPt1
42     and rPt1 are valid coordinates in the image given by begin and
43     end, since no clipping takes place.
44 
45     @param aPt1
46     Start point of the line
47 
48     @param aPt2
49     End point of the line
50 
51     @param color
52     Color value to render the line with
53 
54     @param begin
55     left-top image iterator
56 
57     @param end
58     right-bottom image iterator
59 
60     @param acc
61     Image accessor
62 
63     @param bRoundTowardsPt2
64     Rounding mode to use. Giving false here results in line pixel tend
65     towards pt1, i.e. when a pixel exactly hits the middle between two
66     pixel, the pixel closer to pt1 will be chosen. Giving true here
67     makes renderClippedLine() choose pt2 in those cases.
68  */
69 template< class Iterator, class Accessor >
renderLine(const basegfx::B2IPoint & rPt1,const basegfx::B2IPoint & rPt2,typename Accessor::value_type color,Iterator begin,Accessor acc,bool bRoundTowardsPt2=false)70 void renderLine( const basegfx::B2IPoint&      rPt1,
71                  const basegfx::B2IPoint&      rPt2,
72                  typename Accessor::value_type color,
73                  Iterator                      begin,
74                  Accessor                      acc,
75                  bool                          bRoundTowardsPt2=false )
76 {
77     // code inspired by Paul Heckbert's Digital Line Drawing
78     // (Graphics Gems, Academic Press 1990)
79     const sal_Int32 x1 = rPt1.getX();
80     const sal_Int32 x2 = rPt2.getX();
81     const sal_Int32 y1 = rPt1.getY();
82     const sal_Int32 y2 = rPt2.getY();
83 
84     // TODO(E1): This might overflow
85     sal_Int32 adx = x2 - x1;
86     int sx = 1;
87     if( adx < 0 )
88     {
89         adx *= -1;
90         sx = -1;
91     }
92 
93     // TODO(E1): This might overflow
94     sal_Int32 ady = y2 - y1;
95     int sy = 1;
96     if( ady < 0 )
97     {
98         ady *= -1;
99         sy = -1;
100     }
101 
102     // TODO(P3): handle horizontal and vertical lines specially
103     sal_Int32 xs = x1;
104     sal_Int32 ys = y1;
105     if( adx >= ady )
106     {
107         // semi-horizontal line
108         sal_Int32 rem = 2*ady - adx - !bRoundTowardsPt2;
109         adx *= 2;
110         ady *= 2;
111 
112         Iterator currIter( begin + vigra::Diff2D(0,ys) );
113         typename vigra::IteratorTraits<Iterator>::row_iterator
114             rowIter( currIter.rowIterator() + xs );
115         while(true)
116         {
117             acc.set(color, rowIter);
118 
119             if( xs == x2 )
120                 return;
121 
122             if( rem >= 0 )
123             {
124                 ys += sy;
125                 xs += sx;
126                 currIter.y += sy;
127                 rowIter = currIter.rowIterator() + xs;
128                 rem -= adx;
129             }
130             else
131             {
132                 xs += sx;
133                 rowIter += sx;
134             }
135 
136             rem += ady;
137         }
138 	}
139     else
140     {
141         // semi-vertical line
142         sal_Int32 rem = 2*adx - ady - !bRoundTowardsPt2;
143         adx *= 2;
144         ady *= 2;
145 
146         Iterator currIter( begin + vigra::Diff2D(xs,0) );
147         typename vigra::IteratorTraits<Iterator>::column_iterator
148             colIter( currIter.columnIterator() + ys );
149         while(true)
150         {
151             acc.set(color, colIter);
152 
153             if( ys == y2 )
154                 return;
155 
156             if( rem >= 0 )
157             {
158                 xs += sx;
159                 ys += sy;
160                 currIter.x += sx;
161                 colIter = currIter.columnIterator() + ys;
162                 rem -= ady;
163             }
164             else
165             {
166                 ys += sy;
167                 colIter += sy;
168             }
169 
170             rem += adx;
171         }
172 	}
173 }
174 
175 } // namespace basebmp
176 
177 #endif /* INCLUDED_BASEBMP_LINERENDERER_HXX */
178