File Coverage

blib/lib/Algorithm/Line/Bresenham.pm
Criterion Covered Total %
statement 248 372 66.6
branch 52 106 49.0
condition 8 21 38.1
subroutine 18 20 90.0
pod 8 12 66.6
total 334 531 62.9


line stmt bran cond sub pod time code
1             =head1 NAME
2              
3             Algorithm::Line::Bresenham - simple pixellated line-drawing algorithm
4              
5             =head1 SYNOPSIS
6              
7             use Algorithm::Line::Bresenham qw/line/;
8             my @points = line(3,3 => 5,0);
9             # returns the list: [3,3], [4,2], [4,1], [5,0]
10             my @points = circle(30,30,5);
11             # returns the points to draw a circle centered at 30,30, radius 5
12              
13             =head1 DESCRIPTION
14              
15             Bresenham is one of the canonical line drawing algorithms for pixellated grids.
16             Given a start and an end-point, Bresenham calculates which points on the grid
17             need to be filled to generate the line between them.
18              
19             Googling for 'Bresenham', and 'line drawing algorithms' gives some good
20             overview. The code here are adapted from various sources, mainly from
21             C code at https://gist.github.com/bert/1085538
22              
23             =head1 FUNCTIONS
24              
25             =cut
26              
27              
28             package Algorithm::Line::Bresenham;
29 1     1   60697 use strict; use warnings;
  1     1   2  
  1         27  
  1         11  
  1         3  
  1         33  
30             our $VERSION = 0.14;
31 1     1   5 use base 'Exporter';
  1         1  
  1         180  
32             our @EXPORT_OK = qw/line circle ellipse_rect quad_bezier polyline varthick_line thick_line/;
33              
34              
35             =head2 C
36              
37             line ($from_x, $from_y => $to_x, $to_y);
38              
39             Generates a list of all the intermediate points. This is returned as a list
40             of array references. Previous versions used to include a callback parameter
41             as a CODE ref to act on each point in turn. This version omits that for
42             performance reasons
43              
44             =cut
45              
46             sub line { # ported from https://gist.github.com/bert/1085538
47 1     1   465 use integer;
  1         12  
  1         4  
48 6     6 1 90 my ($x0, $y0, $x1, $y1,$callback)=@_;
49 1     1   49 use integer;
  1         2  
  1         2  
50 6         10 my $dx = abs ($x1 - $x0);
51 6 100       14 my $sx = $x0 < $x1 ? 1 : -1;
52 6         10 my $dy = -abs ($y1 - $y0);
53 6 100       11 my $sy = $y0 < $y1 ? 1 : -1;
54 6         7 my $err = $dx + $dy;
55 6         9 my $e2; #/* error value e_xy */
56             my @points;
57            
58 6         8 while(1){ #/* loop */
59 21         34 push @points,[$x0,$y0];
60 21 100 100     47 last if ($x0 == $x1 && $y0 == $y1);
61 15         17 $e2 = 2 * $err;
62 15 100       32 if ($e2 >= $dy) { $err += $dy; $x0 += $sx; } #/* e_xy+e_x > 0 */
  13         22  
  13         15  
63 15 100       22 if ($e2 <= $dx) { $err += $dx; $y0 += $sy; } #/* e_xy+e_y < 0 */
  10         11  
  10         12  
64             }
65 6         24 return @points;
66             }
67              
68              
69             =head2 C
70              
71             my @points = circle ($x, $y, $radius)
72              
73             Returns the points to draw a circle centered on C<$x,$y> with
74             radius C<$radius>
75              
76             =cut
77              
78             sub circle { # ported from https://gist.github.com/bert/1085538
79 1     1 1 29 my ($xm, $ym, $r)=@_;
80 1     1   148 use integer;
  1         2  
  1         4  
81 1         4 my $x = -$r;
82 1         1 my $y = 0;
83 1         4 my $err = 2-2*$r; #/* II. Quadrant */
84 1         2 my @points;
85 1         2 do {
86 1         2 push @points,[$xm-$x, $ym+$y];# /* I. Quadrant */
87 1         3 push @points,[$xm-$y, $ym-$x];# /* II. Quadrant */
88 1         2 push @points,[$xm+$x, $ym-$y];# /* III. Quadrant */
89 1         2 push @points,[$xm+$y, $ym+$x];# /* IV. Quadrant */
90 1         1 $r = $err;
91 1 50       10 $err += ++$x*2+1 if ($r > $x); #/* e_xy+e_x > 0 */
92 1 50       6 $err += ++$y*2+1 if ($r <= $y); #/* e_xy+e_y < 0 */
93             } while ($x < 0);
94 1         5 return @points;
95             }
96              
97             =head2 C
98              
99             my @points = ellipse_rect ($x0, $y0, $x1, $y1)
100              
101             Returns the points to an ellipse bound within a rectangle defined by
102             the two coordinate pairs passed.
103              
104             =cut
105              
106              
107             sub ellipse_rect{ # ported from https://gist.github.com/bert/1085538
108 1     1   132 use integer;
  1         2  
  1         3  
109 1     1 1 4 my ($x0, $y0, $x1, $y1)=@_;
110 1         3 my $a = abs ($x1 - $x0);
111 1         2 my $b = abs ($y1 - $y0);
112 1         2 my $b1 = $b & 1; #/* values of diameter */
113 1         2 my $dx = 4 * (1 - $a) * $b * $b;
114 1         2 my $dy = 4 * ($b1 + 1) * $a * $a; #/* error increment */
115 1         2 my $err = $dx + $dy + $b1 * $a * $a;
116 1         2 my $e2; #/* error of 1.step */
117              
118 1 50       3 if ($x0 > $x1) { $x0 = $x1; $x1 += $a; } #/* if called with swapped points */
  0         0  
  0         0  
119 1 50       2 $y0 = $y1 if ($y0 >$y1);# /* .. exchange them */
120 1         2 $y0 += ($b + 1) / 2;
121 1         2 $y1 = $y0-$b1; #/* starting pixel */
122 1         1 $a *= 8 * $a; $b1 = 8 * $b * $b;
  1         2  
123 1         2 my @points;
124             do
125 1         1 {
126 3         5 push @points,[$x1, $y0];# /* I. Quadrant */
127 3         6 push @points,[$x0, $y0];# /* II. Quadrant */
128 3         5 push @points,[$x0, $y1];# /* III. Quadrant */
129 3         6 push @points,[$x1, $y1];# /* IV. Quadrant */
130 3         4 $e2 = 2 * $err;
131 3 50       13 if ($e2 >= $dx)
132             {
133 3         6 $x0++;
134 3         3 $x1--;
135 3         5 $err += $dx += $b1; # does this translate into perl
136             } #/* x step */
137 3 50       28 if ($e2 <= $dy)
138             {
139 0         0 $y0++;
140 0         0 $y1--;
141 0         0 $err += $dy += $a;
142             } #/* y step */
143             } while ($x0 <= $x1);
144 1         9 while ($y0-$y1 < $b)
145             { #/* too early stop of flat ellipses a=1 */
146 0         0 push @points,[$x0-1, $y0]; #/* -> finish tip of ellipse */
147 0         0 push @points,[$x1+1, $y0++];
148 0         0 push @points,[$x0-1, $y1];
149 0         0 push @points,[$x1+1, $y1--];
150             }
151            
152 1         5 return @points;
153             }
154              
155             =head2 C
156              
157             my @points = basic_bezier ($x0, $y0, $x1, $y1, $x2, $y2)
158              
159             This is not usefull on its own. Iteturns the points to segment of a
160             bezier curve without a gradient sign change. It is a companion to
161             the C function that splits a bezier into segments
162             with each gradient direction and these segments are computed in
163             C
164              
165             =cut
166              
167              
168             sub basic_bezier{ # without gradient changes adapted from https://gist.github.com/bert/1085538
169 2     2 1 5 my ($x0, $y0, $x1, $y1, $x2, $y2)=@_;
170 2 50       5 my $sx = $x0 < $x2 ? 1 : -1;
171 2 100       5 my $sy = $y0 < $y2 ? 1 : -1; #/* step direction */
172 2         4 my $cur = $sx * $sy *(($x0 - $x1) * ($y2 - $y1) - ($x2 - $x1) * ($y0 - $y1)); #/* curvature */
173 2         3 my $x = $x0 - 2 * $x1 + $x2;
174 2         3 my $y = $y0 - 2 * $y1 +$y2;
175 2         3 my $xy = 2 * $x * $y * $sx * $sy;
176             # /* compute error increments of P0 */
177 2         6 my $dx = (1 - 2 * abs ($x0 - $x1)) * $y * $y + abs ($y0 - $y1) * $xy - 2 * $cur * abs ($y0 - $y2);
178 2         5 my $dy = (1 - 2 * abs ($y0 - $y1)) * $x * $x + abs ($x0 - $x1) * $xy + 2 * $cur * abs ($x0 - $x2);
179             #/* compute error increments of P2 */
180 2         5 my $ex = (1 - 2 * abs ($x2 - $x1)) * $y * $y + abs ($y2 - $y1) * $xy + 2 * $cur * abs ($y0 - $y2);
181 2         6 my $ey = (1 - 2 * abs ($y2 - $y1)) * $x * $x + abs ($x2 - $x1) * $xy - 2 * $cur * abs ($x0 - $x2);
182             # /* sign of gradient must not change */
183 2 50 33     9 warn "gradient change detected" unless (($x0 - $x1) * ($x2 - $x1) <= 0 && ($y0 - $y1) * ($y2 - $y1) <= 0);
184 2 50       11 if ($cur == 0)
185             { #/* straight line */
186 0         0 return line ($x0, $y0, $x2, $y2);
187            
188             }
189 2         5 $x *= 2 * $x;
190 2         3 $y *= 2 * $y;
191 2 100       4 if ($cur < 0)
192             { #/* negated curvature */
193 1         3 $x = -$x;
194 1         2 $dx = -$dx;
195 1         1 $ex = -$ex;
196 1         2 $xy = -$xy;
197 1         1 $y = -$y;
198 1         1 $dy = -$dy;
199 1         1 $ey = -$ey;
200             }
201             #/* algorithm fails for almost straight line, check error values */
202 2 50 33     15 if ($dx >= -$y || $dy <= -$x || $ex <= -$y || $ey >= -$x)
      33        
      33        
203             {
204 0         0 return (line ($x0, $y0, $x1, $y1), line ($x1, $y1, $x2, $y2)); #/* simple approximation */
205             }
206 2         3 $dx -= $xy;
207 2         3 $ex = $dx + $dy;
208 2         2 $dy -= $xy; #/* error of 1.step */
209 2         2 my @points;
210 2         7 while(1)
211             { #/* plot curve */
212 7         19 push @points,[$x0, $y0];
213 7         9 $ey = 2 * $ex - $dy; #/* save value for test of y step */
214 7 50       12 if (2 * $ex >= $dx)
215             { #/* x step */
216 7 100       12 last if ($x0 == $x2);
217 5         6 $x0 += $sx;
218 5         6 $dy -= $xy;
219 5         5 $ex += $dx += $y;
220             }
221 5 100       10 if ($ey <= 0)
222             { #/* y step */
223 2 50       2 last if ($y0 == $y2);
224 2         3 $y0 += $sy;
225 2         3 $dx -= $xy;
226 2         2 $ex += $dy += $x;
227             }
228             }
229 2         6 return @points;
230             }
231              
232              
233             =head2 C
234              
235             my @points = quad_bezier ($x0, $y0, $x1, $y1, $x2, $y2)
236              
237             Draws a Bezier curve from C<($x0,$y0)> to C<($x2,$y2)> using control
238             point C<($x1,$y1)>
239              
240             =cut
241              
242              
243             sub quad_bezier{ # adapted from http://members.chello.at/easyfilter/bresenham.html
244 1     1 1 4 my ($x0, $y0, $x1, $y1, $x2, $y2)=@_;# /* plot any quadratic Bezier curve */
245 1         2 my $x = $x0-$x1;
246 1         2 my $y = $y0-$y1;
247 1         3 my $t = $x0-2*$x1+$x2;
248 1         2 my $r;
249             my @points;
250 1 50       3 if ($x*($x2-$x1) > 0) { #/* horizontal cut at P4? */
251 0 0       0 if ($y*($y2-$y1) > 0){ #/* vertical cut at P6 too? */
252 0 0       0 if (abs(($y0-2*$y1+$y2)/$t*$x) > abs($y)) { #/* which first? */
253 0         0 $x0 = $x2; $x2 = $x+$x1; $y0 = $y2; $y2 = $y+$y1;# /* swap points */
  0         0  
  0         0  
  0         0  
254             } #/* now horizontal cut at P4 comes first */
255             }
256 0         0 $t = ($x0-$x1)/$t;
257 0         0 $r = (1-$t)*((1-$t)*$y0+2.0*$t*$y1)+$t*$t*$y2;# /* By(t=P4) */
258 0         0 $t = ($x0*$x2-$x1*$x1)*$t/($x0-$x1); #/* gradient dP4/dx=0 */
259 0         0 $x = int($t+0.5); $y = int($r+0.5);
  0         0  
260 0         0 $r = ($y1-$y0)*($t-$x0)/($x1-$x0)+$y0; #/* intersect P3 | P0 P1 */
261 0         0 push @points, basic_bezier($x0,$y0, $x,int($r+0.5), $x,$y);
262 0         0 $r = ($y1-$y2)*($t-$x2)/($x1-$x2)+$y2; #/* intersect P4 | P1 P2 */
263 0         0 $x0 = $x1 = $x; $y0 = $y; $y1 = int($r+0.5);# /* P0 = P4, P1 = P8 */
  0         0  
  0         0  
264             }
265 1 50       5 if (($y0-$y1)*($y2-$y1) > 0) { #/* vertical cut at P6? */
266 1         3 $t = $y0-2*$y1+$y2; $t = ($y0-$y1)/$t;
  1         2  
267 1         13 $r = (1-$t)*((1-$t)*$x0+2.0*$t*$x1)+$t*$t*$x2; # /* Bx(t=P6) */
268 1         3 $t = ($y0*$y2-$y1*$y1)*$t/($y0-$y1); #/* gradient dP6/dy=0 */
269 1         2 $x = int($r+0.5); $y = int($t+0.5);
  1         1  
270 1         3 $r = ($x1-$x0)*($t-$y0)/($y1-$y0)+$x0; #/* intersect P6 | P0 P1 */
271 1         4 push @points, basic_bezier($x0,$y0, int($r+0.5),$y, $x,$y);
272 1         3 $r = ($x1-$x2)*($t-$y2)/($y1-$y2)+$x2; #/* intersect P7 | P1 P2 */
273 1         2 $x0 = $x; $x1 = int($r+0.5); $y0 = $y1 = $y;# /* P0 = P6, P1 = P7 */
  1         2  
  1         1  
274             }
275 1         3 push @points, basic_bezier($x0,$y0, $x1,$y1, $x2,$y2); #/* remaining part */
276 1         4 return @points;
277             }
278              
279             =head2 C
280              
281             my @points = polyline ($x0, $y0, $x1, $y1, $x2, $y2)
282              
283             Draws a polyline between points served as a list of x,y pairs
284              
285             =cut
286              
287             sub polyline{
288 1     1 1 3 my @vertices;
289 1         18 push @vertices,[shift,shift] while (@_>1);
290 1         2 my @points;
291 1         4 foreach my $vertex(0..(@vertices-2)){
292 2         3 push @points,line(@{$vertices[$vertex]},@{$vertices[$vertex+1]});
  2         3  
  2         4  
293 2 100       7 pop @points if ($vertex < (@vertices-2)); # remove duplicated points
294             }
295 1         4 return @points;
296             }
297              
298             =head2 C
299              
300             my @points = thick_line ($x0, $y0, $x1, $y1,$thickness)
301              
302             Draws a line thickened using Murphy's modication of Bresenham'salgorithm
303             between two points of x,y pairs. This routine was further enahnced to
304             provide variable thickness lines and uses multiple helper subroutines.
305              
306             =head2 C
307            
308             my @points= varthick_line($x0,$y0,$x1,$y1,$leftFn,$argL,$rightFn,$argR)
309              
310             Variable thickness lines are implemented as described in
311             http://kt8216.unixcab.org/murphy/index.html ; This allows passing of
312             two subroutine references (so the left side and the right sides of the
313             line can have differently varying thicknesses) along with a
314             user originated parameter. The subroutine reference example is shown below:
315              
316             my $leftFn=sub{
317             my ($arg,$p,$l)=@_;
318             # C<$arg> is passed by calling routine,
319             # C<$p> is point on line
320             # C<$l> is length of line
321             return $p % $arg;
322             };
323              
324             =cut
325              
326             ## Variable thickness lines using Murphy's Modification of Bresenham Line Algorithm**
327             ## Codes ported from C in http://kt8216.unixcab.org/murphy/index.html
328              
329             #* X BASED LINES *
330            
331             sub x_perpendicular{
332 0     0 0 0 my ($x0,$y0,$dx,$dy,$xstep,$ystep,$einit,$w_left,$w_right,$winit)=@_;
333            
334 0         0 my @pts;
335              
336 0         0 my $threshold = $dx - 2*$dy;
337 0         0 my $E_diag= -2*$dx;
338 0         0 my $E_square= 2*$dy;
339 0         0 my $p=my $q=0;
340              
341 0         0 my $y= $y0;
342 0         0 my $x= $x0;
343 0         0 my $error= $einit;
344 0         0 my $tk= $dx+$dy-$winit;
345              
346 0         0 while($tk<=$w_left)
347             {
348 0         0 push (@pts,[$x,$y]);
349 0 0       0 if ($error>=$threshold)
350             {
351 0         0 $x= $x + $xstep;
352 0         0 $error = $error + $E_diag;
353 0         0 $tk= $tk + 2*$dy;
354             }
355 0         0 $error = $error + $E_square;
356 0         0 $y= $y + $ystep;
357 0         0 $tk= $tk + 2*$dx;
358 0         0 $q++;
359             }
360              
361 0         0 $y= $y0;
362 0         0 $x= $x0;
363 0         0 $error= -$einit;
364 0         0 $tk= $dx+$dy+$winit;
365              
366 0         0 while($tk<=$w_right)
367             {
368 0 0       0 push (@pts,[$x,$y]) if ($p);
369 0 0       0 if ($error>$threshold)
370             {
371 0         0 $x= $x - $xstep;
372 0         0 $error = $error + $E_diag;
373 0         0 $tk= $tk + 2*$dy;
374             }
375 0         0 $error = $error + $E_square;
376 0         0 $y= $y - $ystep;
377 0         0 $tk= $tk + 2*$dx;
378 0         0 $p++;
379             }
380              
381 0 0 0     0 push (@pts,[$x,$y]) if ($q==0 && $p<2); # we need this for very thin lines
382            
383 0         0 return @pts;
384             }
385              
386              
387             sub x_varthick_line{
388 0     0 0 0 my ($x0,$y0,$dx,$dy,$xstep,$ystep,
389             $left, $argL, #left thickness function
390             $right,$argR, #right thickness function
391             $pxstep,$pystep)=@_;
392            
393 0         0 my @xPoints;
394            
395 0         0 my $p_error= 0;
396 0         0 my $error= 0;
397 0         0 my $y= $y0;
398 0         0 my $x= $x0;
399 0         0 my $threshold = $dx - 2*$dy;
400 0         0 my $E_diag= -2*$dx;
401 0         0 my $E_square= 2*$dy;
402 0         0 my $length = $dx+1;
403 0         0 my $D= sqrt($dx*$dx+$dy*$dy);
404              
405 0         0 for(my $p=0;$p<$length;$p++)
406             {
407 0         0 my $w_left= $left->($argL, $p, $length)*2*$D;
408 0         0 my $w_right= $right->($argR,$p, $length)*2*$D;
409 0         0 push @xPoints,x_perpendicular($x,$y, $dx, $dy, $pxstep, $pystep,
410             $p_error,$w_left,$w_right,$error);
411 0 0       0 if ($error>=$threshold)
412             {
413 0         0 $y= $y + $ystep;
414 0         0 $error = $error + $E_diag;
415 0 0       0 if ($p_error>=$threshold)
416             {
417 0         0 push @xPoints,x_perpendicular($x,$y, $dx, $dy, $pxstep, $pystep,
418             ($p_error+$E_diag+$E_square),
419             $w_left,$w_right,$error);
420 0         0 $p_error= $p_error + $E_diag;
421             }
422 0         0 $p_error= $p_error + $E_square;
423             }
424 0         0 $error = $error + $E_square;
425 0         0 $x= $x + $xstep;
426             }
427 0         0 return @xPoints;
428             }
429              
430             #* Y BASED LINES *
431              
432             sub y_perpendicular{
433 23     23 0 40 my ($x0,$y0,$dx,$dy,$xstep,$ystep,
434             $einit,$w_left, $w_right,$winit)=@_;
435              
436 23         23 my @pts;
437              
438 23         30 my $threshold = $dy - 2*$dx;
439 23         26 my $E_diag= -2*$dy;
440 23         24 my $E_square= 2*$dx;
441 23         25 my $p=my $q=0;
442              
443 23         25 my $y= $y0;
444 23         27 my $x= $x0;
445 23         27 my $error= -$einit;
446 23         28 my $tk= $dx+$dy+$winit;
447              
448              
449 23         35 while($tk<=$w_left)
450             {
451 43         85 push @pts,[$x,$y];
452 43 100       65 if ($error>$threshold)
453             {
454 21         28 $y= $y + $ystep;
455 21         22 $error = $error + $E_diag;
456 21         24 $tk= $tk + 2*$dx;
457             }
458 43         49 $error = $error + $E_square;
459 43         44 $x= $x + $xstep;
460 43         61 $tk= $tk + 2*$dy;
461 43         396 $q++;
462             }
463              
464              
465 23         26 $y= $y0;
466 23         30 $x= $x0;
467 23         24 $error= $einit;
468 23         26 $tk= $dx+$dy-$winit;
469              
470 23         35 while($tk<=$w_right)
471             {
472 38 100       68 push (@pts,[$x,$y]) if ($p);
473 38 100       51 if ($error>=$threshold)
474             {
475 17         20 $y= $y - $ystep;
476 17         17 $error = $error + $E_diag;
477 17         26 $tk= $tk + 2*$dx;
478             }
479 38         64 $error = $error + $E_square;
480 38         43 $x= $x - $xstep;
481 38         40 $tk= $tk + 2*$dy;
482 38         59 $p++;
483             }
484              
485 23 50 33     36 push (@pts,[$x,$y]) if ($q==0 && $p<2); # we need this for very thin lines
486 23         55 return @pts;
487             }
488              
489              
490             sub y_varthick_line {
491 1     1 0 3 my ($x0,$y0,$dx,$dy,$xstep,$ystep,
492             $left, $argL, #left thickness function
493             $right,$argR, #right thickness function
494             $pxstep,$pystep)=@_;
495            
496 1         1 my @yPoints;
497 1         2 my $p_error= 0;
498 1         1 my $error= 0;
499 1         13 my $y= $y0;
500 1         3 my $x= $x0;
501 1         4 my $threshold = $dy - 2*$dx;
502 1         2 my $E_diag= -2*$dy;
503 1         1 my $E_square= 2*$dx;
504 1         2 my $length = $dy+1;
505 1         2 my $D= sqrt($dx*$dx+$dy*$dy);
506              
507 1         4 for(my $p=0;$p<$length;$p++)
508             {
509 19         33 my $w_left= $left->($argL, $p, $length)*2*$D;
510 19         31 my $w_right= $right->($argR,$p, $length)*2*$D;
511 19         27 push @yPoints,y_perpendicular($x,$y, $dx, $dy, $pxstep, $pystep,
512             $p_error,$w_left,$w_right,$error);
513 19 100       31 if ($error>=$threshold)
514             {
515 8         10 $x= $x + $xstep;
516 8         9 $error = $error + $E_diag;
517 8 100       13 if ($p_error>=$threshold)
518             {
519 4         7 push @yPoints,y_perpendicular($x,$y, $dx, $dy, $pxstep, $pystep,
520             ($p_error+$E_diag+$E_square),$w_left,$w_right,$error);
521 4         5 $p_error= $p_error + $E_diag;
522             }
523 8         9 $p_error= $p_error + $E_square;
524             }
525 19         20 $error = $error + $E_square;
526 19         39 $y= $y + $ystep;
527             }
528 1         9 return @yPoints;
529             }
530              
531             #* ENTRY *
532              
533             sub thick_line{
534 1     1 1 5 my ($x0,$y0,$x1,$y1,$thickness)=@_;
535 1     19   7 return varthick_line(13,13,5,-5,sub{return $thickness},undef,sub{return $thickness},2)
  19         23  
  19         35  
536             };
537              
538              
539             sub varthick_line{
540 1     1 1 3 my ($x0,$y0,$x1,$y1,
541             $left,$argL,
542             $right,$argR)=@_;
543              
544 1         2 my $dx= $x1-$x0;
545 1         2 my $dy= $y1-$y0;
546 1         2 my $xstep= my $ystep= 1;
547              
548 1 50       4 if ($dx<0) { $dx= -$dx; $xstep= -1; }
  1         2  
  1         1  
549 1 50       4 if ($dy<0) { $dy= -$dy; $ystep= -1; }
  1         27  
  1         4  
550              
551 1 50       3 $xstep= 0 if ($dx==0);
552 1 50       3 $ystep= 0 if ($dy==0);
553 1         1 my $pxstep; my $pystep;
554              
555 1         2 my $xch= 0;
556 1         4 for($xstep + $ystep*4){
557 1 50       3 ($_==-1 + -1*4) && do {$pystep= -1; $pxstep= 1; $xch= 1; last;}; # -5
  1         1  
  1         2  
  1         1  
  1         2  
558 0 0       0 ($_==-1 + 0*4) && do {$pystep= -1; $pxstep= 0; $xch= 1; last;}; # -1
  0         0  
  0         0  
  0         0  
  0         0  
559 0 0       0 ($_==-1 + 1*4) && do {$pystep= 1; $pxstep= 1; last;}; # 3
  0         0  
  0         0  
  0         0  
560 0 0       0 ($_== 0 + -1*4) && do {$pystep= 0; $pxstep= -1; last;}; # -4
  0         0  
  0         0  
  0         0  
561 0 0       0 ($_== 0 + 0*4) && do {$pystep= 0; $pxstep= 0; last;}; # 0
  0         0  
  0         0  
  0         0  
562 0 0       0 ($_== 0 + 1*4) && do {$pystep= 0; $pxstep= 1; last;}; # 4
  0         0  
  0         0  
  0         0  
563 0 0       0 ($_== 1 + -1*4) && do {$pystep= -1; $pxstep= -1; last;}; # -3
  0         0  
  0         0  
  0         0  
564 0 0       0 ($_== 1 + 0*4) && do {$pystep= -1; $pxstep= 0; last;}; # 1
  0         0  
  0         0  
  0         0  
565 0 0       0 ($_== 1 + 1*4) && do {$pystep= 1; $pxstep= -1; $xch=1; last;}; # 5
  0         0  
  0         0  
  0         0  
  0         0  
566             }
567              
568 1 50       2 if ($xch){
569 1         2 my $K;
570 1         1 $K= $argL; $argL= $argR; $argR= $K;
  1         2  
  1         1  
571 1         2 $K= $left; $left= $right; $right= $K; }
  1         1  
  1         8  
572              
573 1 50       4 if ($dx>$dy){
574 0         0 return x_varthick_line($x0,$y0,$dx,$dy,$xstep,$ystep,
575             $left,$argL,$right,$argR,
576             $pxstep,$pystep);
577             }
578             else{
579 1         7 return y_varthick_line($x0,$y0,$dx,$dy,$xstep,$ystep,
580             $left,$argL,$right,$argR,
581             $pxstep,$pystep);
582             }
583             }
584              
585              
586              
587              
588             1;
589             __END__