Converting Bresenham's line plotting algorithm

stan74

Senior Member
My last not working effort.
Rich (BB code):
; === DRAW a LINE....as if
; Inputs are X1, Y1, X2, Y2: Destroys value of X1, Y1
;
symbol x1=w0
symbol x2=w1
symbol y1=w2
symbol y2=w3
symbol dx=w4
symbol dy=w5
symbol er=w6
symbol temp1=w6
;
let dx=x2-x1:if dx bit 15 set then dec dx:let dx=dx not dx:endif ;is dx negative?
let dy=y2-y1:if dx bit 15 set then dec dx:let dx=dx not dx:endif ;is dy negative?
let er = 2*dy?dx:if er bit 15 set then dec er:let er=er not er:endif ;is er negative?
let px=x1
let py=y1
;
do
gosub plot ;plot pixel
if px=x2 and py=y2 then return:endif
if er bit 15 set then let er=2*dy+er:endif ;if er < 0
inc px
if er bit 15 clear then let er=2*dy+er:let temp1=2*dx:let er=er-temp1 ;if er > 0
inc px
inc py
loop
 

AllyCat

Senior Member
Hi,,

I've spent too much time trying to convert this program to picaxe basic. Darn those negative numbers.
Seems to be completely Off Topic, and not so much a negative number issue but numerous syntax errors:

if dx bit 15 set then is not valid, use if dx > $7fff then
dx=dx not dx is not valid, I guess you want dx = not dx for the complement
I'm not sure what er = 2*dy?dx is supposed to do, particularly as the algorithm calls for division by 2 :

That's the one area where the negative is a little tricky, because you need to extend the sign: A number > 32767 (i.e. negative) when divided by 2 will always be < 32768 (i.e. positive). I don't know if there's a better general purpose sign extension routine, but you could use:

if er < $8000 then : er = er / 2 else er = not er / 2 xor $ffff endif. Strictly, there are a few ":"s missing in there, but the PE compiler appears to understand. :)

Cheers, Alan.
 

stan74

Senior Member
Hi Alan. The code I'm trying to convert simple code,(link previous post in all languages that use negative numbers) and have rewritten it many times with no sucess. I've commented this. If a word var goes negative bit 15 is set so subtract 1 and invert the word..or is that wrong? Simple basic code I did on a zx81 now seems difficult..but then I'm 62 now :)
Rich (BB code):
line:
if x2>x1 then let dx=x2-x1
else let dx=x1-x2:endif ;abs dx

if y2>y1 then let dx=y2-y1
else let dx=y1-y2:endif ;abs dy

let er = 2*dy-dx:if er bit 15 set then ;is er negative?
                  dec er:let er=not er
                  endif
let px=x1
let py=y1
;
do
gosub plot ;plot pixel
if px=x2 and py=y2 then return:endif
if er bit 15 set then let er=2*dy+er:endif ;if er < 0
inc px
if er bit 15 clear then ;if er > 0
      let er=2*dy+er
      let temp1=2*dx:let er=er-temp1
      if er bit 15 set then ;is er negative?
            dec er:let er=not er
      endif
endif
inc px
inc py
loop
 

stan74

Senior Member
PS. I did try <32768 negative >32768 positive but I lost track checking the absolute value and branching on the sign. Adding not multiply by 2 would not confuse things. I've stepped through the program on paper but not sure about the math.
 

AllyCat

Senior Member
Hi,

Any variable bit 15 is NOT a valid PICaxe syntax !

bit15 (with no space) is specifically the MSB of W0 and/or the MSB of B1 (all three overlay each other in RAM). Personally, I also prefer to avoid operators such as bit set (and << or >>, etc) because they work only with X2 chips. Adding a variable to itself is marginally faster than multiplication by 2 (or shifting bits left), but the algorithm appears to require division by 2 (or shifting right).

Yes, when converting positive/negative numbers in twos complement it's necessary to add or subtract 1. But with PICaxe the use of the IF..THEN..ELSE..ENDIF structure is often the easiest and best method, so the +/-1 may not be needed (my example in #14 seemed to correctly cross though zero on the simulator). IMHO the omission of a Carry bit with PICaxe is a real pain. :(

Converting one of the (Basic) routines shown in your link doesn't look too difficult, but I don't propose to do it at the moment. I'm not convinced that all the versions are truly "equivalent" and PICaxe Basic of course doesn't have a PLOT command of any type.

Cheers, Alan.

PS: Actually you're quite young compared with many of us on this forum, who also cut our teeth on a Z80 (or maybe an even older processor/computer). ;)

PPS: In twos complement, negative is > 32767 (or > $7FFF).
 

stan74

Senior Member
I didn't want to hi-jack the thread Alan. There's no division in the code, that's what's emphasised about Bresenham's line algorithm,just addition and subtraction which makes it fast. It's for a 128x64 oled,the RE one has a pic that controls it. I can plot a pixel at any x,y point and lines are just plots between start x,y and end x,y. Just found more sites to check with libraries. Even more off subject,I been using Great Cow Basic and just now Free Basic Compiler, have a look...on a Rasperry Pi,which is Linux and complicated but it's very powerful and much faster than Python. I never took to C or C++.
 

AllyCat

Senior Member
Hi,

Yes, I read the bit (somewhere) about no division, but it's there in most of the code versions, Line 1550 in the (basic) Basic version (below). Only division by 2 (once), so it's a simple right-shift which is dead easy with most microcontrollers, but not (for 16-17 bits) in PICaxe Basic. :(

However, apart from that, I don't see any significant problems in converting the code for any PICaxe (not even an X2). Some PICaxe syntax is a little unusual but it should all be in Manual 2 (or the on-line command help). If in doubt there's the syntax checker and Simulator in the (Windows) Program Editor, probably better without all those multi-line commands separated by ":"s .

Code:
 1500 REM === DRAW a LINE. Ported from C version
 1510 REM Inputs are X1, Y1, X2, Y2: Destroys value of X1, Y1
 1520 DX = ABS(X2 - X1):SX = -1:IF X1 < X2 THEN SX = 1
 1530 DY = ABS(Y2 - Y1):SY = -1:IF Y1 < Y2 THEN SY = 1
 1540 ER = -DY:IF DX > DY THEN ER = DX
 [B]1550 ER = INT(ER / 2)[/B]    ; (Signed) Division by 2 !
 1560 PLOT X1,Y1:REM This command may differ depending ON BASIC dialect
 1570 IF X1 = X2 AND Y1 = Y2 THEN RETURN
 1580 E2 = ER
 1590 IF E2 > -DX THEN ER = ER - DY:X1 = X1 + SX
 1600 IF E2 < DY THEN ER = ER + DX:Y1 = Y1 + SY
 1610 GOTO 1560
If the OP has more to discuss on the original topic, then I'm sure one of the moderators can strip off this section to create a new thread.

Cheers, Alan.
 

hippy

Technical Support
Staff member
Technically "IF var BIT bit SET/CLEAR THEN" is valid code ...

http://www.picaxe.com/BASIC-Commands/Program-Flow-Control/if-bit

Also negation done long-hand binary is; invert then add one, not the other way round. But may as well just use "let var=-var" as the PICAXE supports that.

If someone can tell me where the above posts are meant to be I can move them there, or into a new thread.
 

AllyCat

Senior Member
Hi,

Technically "IF var BIT bit SET/CLEAR THEN" is valid code ....
But only if you put #PICAXE 20X2 (or similar) at the top of your code. ;)

Also I note that IF w1 BIT 15 SET ... generates twice as many code bytes as IF w1 => $8000 ... :D

I must admit that I'm rather surprised that a single line like: IF w1 BIT 15 SET THEN DEC w1 w1 = NOT w1 b4 = -1 ENDIF (with no colons) passes the syntax check. Seems strange for an "educational" language (but perhaps some would say the same about GOTO).
___

Since this now bears so little relationship with the original thread title, I'd suggest breaking off the last two lines of #12 ("I've spent....") onwards to create a new thread titled something like "Converting Bresenham's line algorithm to plot a line".

Cheers, Alan.
 

stan74

Senior Member
hippy "Also negation done long-hand binary is; invert then add one, not the other way round. But may as well just use "let var=-var" as the PICAXE supports that."
But you can't use if var<0 because it never is.
 

hippy

Technical Support
Staff member
But you can't use if var<0 because it never is.
That is correct, but if you want to perform an ABS function, make a two's complement negative variable positive, then this will work ...

Code:
If w0 >= $8000 Then
  w0 = -w0
End If
You can use a #MACRO to make that more readable
Code:
#Macro If_Negative( wVar )
If wVar >= $8000 Then
#EndMacro

If_Negative(w0)
  w0 = -w0
End If
 

stan74

Senior Member
Ta for that hippy.I bet other picaxe users have had problems with negative numbers. I've spent too much time on this. If the line is start x,y and end x,y the slope is.. end x-start x/end y-start y. If the result is positive and >=1 then
for x_plot_coord t=start x to end x
calculate y_plot_coord ;easy
next
If the slope is <1 then
for y_plot_coord=start_y to end_y
calculate x_plot_coord
next
if I copy the above 3 times and swap values for
case1 startx<endx/starty<endy
case2 startx>endx/starty<endy
case3 startx<endx/starty>endy
case4 startx<endx/starty<endy
It's no negative numbers but I haven't used case so it was 8 lots of similar code and I couldn't get it to switch when the slope was <1
Like lines from 0,0 0,63 to 0,0 63,63 would increase x in a for y loop
and lines from 0,0 64,63 to 0,0 127,63 would increase y in a for x loop.
You can't read a serial oleds screen ram else I could just or 1 byte instead of sending a 1K buffer. I've got a 2 year old £5 component tester that shows how cheap displays are nowadays.SAM_1219.JPG
 

AllyCat

Senior Member
Hi,

It seems that although the algorithm is able to use (positive) integers and no division, almost all the examples from your link in #1 do not meet that criterion (I don't intend to flog through the Assembler version). :(

Furthermore, the "Basic" version claims to be ported from the C ; I'm not sufficiently comfortable with C to be certain, but I'm fairly sure that the Basic version is INCORRECT. It appears to have several spurious "-" signs (not present in the other versions) and sets the error term as an integer when it isn't.

Therefore, the BBC Basic version seems a far better starting point, it's obvious which variables are integers (or more importantly which isn't) and the structure for handling all 8 octants is more obvious. So I've ported it to PICaxe Basic, removing the division by 2 (and thus the non-integer element), scaling the iteration accordingly.

Here is my version, not fully tested but it appears to give the expected results. For a 128 x 64 screen, byte values may be (mainly) sufficient, but some modification will be required if you want the origin at the centre of the screen (i.e. to accommodate negative input values).

Code:
REM === DRAW a LINE. Ported from BBC Basic version.  AllyCat December 2016.
REM Inputs are X1, Y1, X2, Y2: Destroys value of X1, Y1

#picaxe 08m2                ; And almost any other
symbol x1 = b1
symbol x2 = b2
symbol y1 = b3 
symbol y2 = b4
symbol dx = b5
symbol dy = b6
symbol sx = b7
symbol sy = b8
symbol er = w9 
symbol maxpos = $7fff
 
x1 = 0    ; Test data
y1 = 10
x2 = 10
y2 = 3

	if x1 < x2 then : sx = 1 : dx = x2 - x1 : else sx = -1 : dx = x1 - x2 : endif
	if y1 < y2 then : sy = 1 : dy = y2 - y1 : else sy = -1 : dy = y1 - y2 : endif
	if dx > dy then : er = dx : else er = dy : endif       			   ; Don't divide "er" by 2
do
	call plot
	if x1 = x2 and y1 = y2 then exit				; Or return from subroutine
		if dx > dy then
			x1 = x1 + sx : er = er - dy - dy		; Subtract twice as "er" is doubled
			if er > maxpos then 				; It's Negative
				er = er + dx + dx : y1 = y1 + sy : endif 
		else
			y1 = y1 + sy : er = er - dx - dx
			if er > maxpos then 
				er = er + dy + dy : x1 = x1 + sx : endif
		endif
loop
	end
plot:
	sertxd(cr,#x1," ",#y1)
return
Cheers, Alan.
 

hippy

Technical Support
Staff member
Furthermore, the "Basic" version claims to be ported from the C ; I'm not sufficiently comfortable with C to be certain, but I'm fairly sure that the Basic version is INCORRECT.
I am not entirely convinced any of the integer versions are correct or would work for all possible line slopes though I am not familiar with Bresenham's algorithm. Maybe we should start from first principles as that should deliver a PICAXE oriented solution rather than trying to bash a square peg through a round hole ...

The principle is simple enough. Start with a piece of squared paper with (0,0) at the bottom left, (X,Y) at the top right, then a line from somewhere upwards and to the right would require stepping along the horizontal X-axis a square at a time and adjusting where Y will be for each step. Our start case requires the line's X distance to be greater than the Y distance.

For a line from (1,1) to (7,3)(7,4) we would like to go up 0.3 of a square for every step along ( left image below ). However we can only go up 0 or 1 units.

Note it's a maximum of 1 because otherwise the Y distance is longer, and we'd 'turn everything on its side' and step along the Y-axis a unit at a time.

What Bresenham's algorithm seeks to determine is when we should go up an additional Y unit, the +1 every few steps rather than the 0 our rounded down 0.3 would give us every step.

Apart from the fact that Y could actually be going down, Bresenham's 'fiddle factor' seems to be only place where negative numbers are required, and it seems that could equally be a positive which is decremented rather than a negative which is incremented.

The algorithms presented handle going right to left, but it's easy enough to handle that by swapping the points around so that case also becomes left to right. The core algorithm would then be ...

Code:
Sub_DrawLine:
  dx = x - xEnd : If dx >= $80 Then : dx = -dx : End If
  dy = y - yEnd : If dy >= $80 Then : dy = -dy : End If
  If dx > dy Then
    ; Step along X-axis in one pixel steps
    If x > xEnd Then
      Swap x, xEnd
      Swap y, yEnd
    End If
    SetPixel(x,y,"X")
    Do Until x = xEnd
      x = x + 1
      y = y + ? ; <------ ?
      SetPixel(x,y,"X")
    Loop
  Else
    ; Step along Y-axis in one pixel steps
    If y > yEnd Then
      Swap y, yEnd
      Swap x, xEnd
    End If
    SetPixel(x,y,"Y")
    Do Until y = yEnd
      y = y + 1
      x = x + ? ; <------ ?
      SetPixel(x,y,"Y")
    Loop
  End If
  Return
And the only thing then left is to determine what the increments at the places marked should be. I'll have to read up on Bresenham's algorithm to figure that out.
 

Attachments

Last edited:

hippy

Technical Support
Staff member
This seems to work for me with a few tweaks. Attached code creates a virtual 16 x 64 screen in scratchpad which it draws onto and displays. Best to run it on a real 28X2 or 40X2 as it seems it may have revealed a simulation bug.

Note that DD in the program must be a word variable. You should see something like this on the Terminal display ...

Code:
15 : ................................................................
14 : ................................................................
   :
 4 : ................................................................
 3 : ......**........................................................
 2 : ...***..........................................................
 1 : .**.............................................................
 0 : ................................................................
     0123456789-123456789-123456789-123456789-123456789-123456789-123
 

Attachments

stan74

Senior Member
Wow! Plenty to look at here. How did you use single letters for vars? I'll see if it works in different directions. Code like this is used in plotters apparently. This looks easy to work with. I bought a 3 axis accelerometer thingy but think I leave it in the packet 'till after Christmas because it uses NEGATIVE numbers :)
int x,y,dx,dy,dx1,dy1,px,py,xe,ye,i;
033
dx=x2-x1;
034
dy=y2-y1;
035
dx1=fabs(dx);
036
dy1=fabs(dy);
037
px=2*dy1-dx1;
038
py=2*dx1-dy1;
039
if(dy1<=dx1)
040
{
041
if(dx>=0)
042
{
043
x=x1;
044
y=y1;
045
xe=x2;
046
}
047
else
048
{
049
x=x2;
050
y=y2;
051
xe=x1;
052
}
053
putpixel(x,y,c);
054
for(i=0;x<xe;i++)
055
{
056
x=x+1;
057
if(px<0)
058
{
059
px=px+2*dy1;
060
}
061
else
062
{
063
if((dx<0 && dy<0) || (dx>0 && dy>0))
064
{
065
y=y+1;
066
}
067
else
068
{
069
y=y-1;
070
}
071
px=px+2*(dy1-dx1);
072
}
073
delay(0);
074
putpixel(x,y,c);
075
}
076
}
077
else
078
{
079
if(dy>=0)
080
{
081
x=x1;
082
y=y1;
083
ye=y2;
084
}
085
else
086
{
087
x=x2;
088
y=y2;
089
ye=y1;
090
}
091
putpixel(x,y,c);
092
for(i=0;y<ye;i++)
093
{
094
y=y+1;
095
if(py<=0)
096
{
097
py=py+2*dx1;
098
}
099
else
100
{
101
if((dx<0 && dy<0) || (dx>0 && dy>0))
102
{
103
x=x+1;
104
}
105
else
106
{
107
x=x-1;
108
}
109
py=py+2*(dx1-dy1);
110
}
111
delay(0);
112
putpixel(x,y,c);
113
}
114
}
115
}
 

stan74

Senior Member
I tried your Sub_Line code.It works for positive lines ie xEnd>x,yEnd.y but not x>xEnd. Haven't tried y>yEnd yet. It's late.SAM_1228.JPGSAM_1221.JPG
 

hippy

Technical Support
Staff member
I tried your Sub_Line code.It works for positive lines ie xEnd>x,yEnd.y but not x>xEnd. Haven't tried y>yEnd yet. It's late.
Thanks for testing. I'll have to take a look at the code when I get a few spare seconds. Hopefully it's something obvious which is easy to fix.
 

stan74

Senior Member
I am not entirely convinced any of the integer versions are correct or would work for all possible line slopes though I am not familiar with Bresenham's algorithm. Maybe we should start from first principles as that should deliver a PICAXE oriented solution rather than trying to bash a square peg through a round hole ...

The principle is simple enough. Start with a piece of squared paper with (0,0) at the bottom left, (X,Y) at the top right, then a line from somewhere upwards and to the right would require stepping along the horizontal X-axis a square at a time and adjusting where Y will be for each step. Our start case requires the line's X distance to be greater than the Y distance.

For a line from (1,1) to (7,3)(7,4) we would like to go up 0.3 of a square for every step along ( left image below ). However we can only go up 0 or 1 units.

Note it's a maximum of 1 because otherwise the Y distance is longer, and we'd 'turn everything on its side' and step along the Y-axis a unit at a time.

What Bresenham's algorithm seeks to determine is when we should go up an additional Y unit, the +1 every few steps rather than the 0 our rounded down 0.3 would give us every step.

Apart from the fact that Y could actually be going down, Bresenham's 'fiddle factor' seems to be only place where negative numbers are required, and it seems that could equally be a positive which is decremented rather than a negative which is incremented.

The algorithms presented handle going right to left, but it's easy enough to handle that by swapping the points around so that case also becomes left to right. The core algorithm would then be ...

Code:
Sub_DrawLine:
  dx = x - xEnd : If dx >= $80 Then : dx = -dx : End If
  dy = y - yEnd : If dy >= $80 Then : dy = -dy : End If
  If dx > dy Then
    ; Step along X-axis in one pixel steps
    If x > xEnd Then
      Swap x, xEnd
      Swap y, yEnd
    End If
    SetPixel(x,y,"X")
    Do Until x = xEnd
      x = x + 1
      y = y + ? ; <------ ?
      SetPixel(x,y,"X")
    Loop
  Else
    ; Step along Y-axis in one pixel steps
    If y > yEnd Then
      Swap y, yEnd
      Swap x, xEnd
    End If
    SetPixel(x,y,"Y")
    Do Until y = yEnd
      y = y + 1
      x = x + ? ; <------ ?
      SetPixel(x,y,"Y")
    Loop
  End If
  Return
I'm converting last code
And the only thing then left is to determine what the increments at the places marked should be. I'll have to read up on Bresenham's algorithm to figure that out.
You haven't calculated px,py for plot subroutine Alan. Ta though init. I'm converting the last "c like" code I posted because it looks EASY ha-ha, to convert.Ta for the help sofar..get back with working picaxe code soon I hope
 

stan74

Senior Member
REM === DRAW a LINE. Ported from BBC Basic version. AllyCat December 2016.
REM Inputs are X1, Y1, X2, Y2: Destroys value of X1, Y1

#picaxe 08m2 ; And almost any other
symbol x1 = b1
symbol x2 = b2
symbol y1 = b3
symbol y2 = b4
symbol dx = b5
symbol dy = b6
symbol sx = b7
symbol sy = b8
symbol er = w9
symbol maxpos = $7fff

x1 = 0 ; Test data
y1 = 10
x2 = 10
y2 = 3

if x1 < x2 then : sx = 1 : dx = x2 - x1 : else sx = -1 : dx = x1 - x2 : endif
if y1 < y2 then : sy = 1 : dy = y2 - y1 : else sy = -1 : dy = y1 - y2 : endif
if dx > dy then : er = dx : else er = dy : endif ; Don't divide "er" by 2
do
call plot
if x1 = x2 and y1 = y2 then exit ; Or return from subroutine
if dx > dy then
x1 = x1 + sx : er = er - dy - dy ; Subtract twice as "er" is doubled
if er > maxpos then ; It's Negative
er = er + dx + dx : y1 = y1 + sy : endif
else
y1 = y1 + sy : er = er - dx - dx
if er > maxpos then
er = er + dy + dy : x1 = x1 + sx : endif
endif
loop
end
plot:
sertxd(cr,#x1," ",#y1)
return

sorry,for Alan
 

BESQUEUT

Senior Member
Code:
REM === DRAW a LINE. Ported from BBC Basic version.  AllyCat December 2016.
REM Inputs are X1, Y1, X2, Y2: Destroys value of X1, Y1

#picaxe 08m2                ; And almost any other
symbol x1 = b1
symbol x2 = b2
symbol y1 = b3 
symbol y2 = b4
symbol dx = b5
symbol dy = b6
symbol sx = b7
symbol sy = b8
symbol er = w9 
symbol maxpos = $7fff
 
x1 = 0    ; Test data
y1 = 10
x2 = 10
y2 = 3

	if x1 < x2 then : sx = 1 : dx = x2 - x1 : else sx = -1 : dx = x1 - x2 : endif
	if y1 < y2 then : sy = 1 : dy = y2 - y1 : else sy = -1 : dy = y1 - y2 : endif
	if dx > dy then : er = dx : else er = dy : endif       			   ; Don't divide "er" by 2
do
	call plot
	if x1 = x2 and y1 = y2 then exit				; Or return from subroutine
		if dx > dy then
			x1 = x1 + sx : er = er - dy - dy		; Subtract twice as "er" is doubled
			if er > maxpos then 				; It's Negative
				er = er + dx + dx : y1 = y1 + sy : endif 
		else
			y1 = y1 + sy : er = er - dx - dx
			if er > maxpos then 
				er = er + dy + dy : x1 = x1 + sx : endif
		endif
loop
	end
plot:
	sertxd(cr,#x1," ",#y1)
return
sorry,for Alan
As dx and dy never change, you can test only one time for speed optimisation :
Code:
[color=Green]REM === DRAW a LINE. Ported from BBC Basic version. AllyCat December 2016.
REM Inputs are X1, Y1, X2, Y2: Destroys value of X1, Y1
REM JYB optimised[/color]

[color=Navy]#picaxe [/color][color=Black]08m2 [/color][color=Green]; And almost any other[/color]
[color=Blue]symbol [/color][color=Black]x1 [/color][color=DarkCyan]= [/color][color=Purple]b1[/color]
[color=Blue]symbol [/color][color=Black]x2 [/color][color=DarkCyan]= [/color][color=Purple]b2[/color]
[color=Blue]symbol [/color][color=Black]y1 [/color][color=DarkCyan]= [/color][color=Purple]b3 [/color]
[color=Blue]symbol [/color][color=Black]y2 [/color][color=DarkCyan]= [/color][color=Purple]b4[/color]
[color=Blue]symbol [/color][color=Black]dx [/color][color=DarkCyan]= [/color][color=Purple]b5[/color]
[color=Blue]symbol [/color][color=Black]dy [/color][color=DarkCyan]= [/color][color=Purple]b6[/color]
[color=Blue]symbol [/color][color=Black]sx [/color][color=DarkCyan]= [/color][color=Purple]b7[/color]
[color=Blue]symbol [/color][color=Black]sy [/color][color=DarkCyan]= [/color][color=Purple]b8[/color]
[color=Blue]symbol [/color][color=Black]er [/color][color=DarkCyan]= [/color][color=Purple]w9 [/color]
[color=Blue]symbol [/color][color=Black]maxpos [/color][color=DarkCyan]= [/color][color=Navy]$7fff[/color]

[color=Black]x1 [/color][color=DarkCyan]= [/color][color=Navy]0 [/color][color=Green]; Test data[/color]
[color=Black]y1 [/color][color=DarkCyan]= [/color][color=Navy]10[/color]
[color=Black]x2 [/color][color=DarkCyan]= [/color][color=Navy]10[/color]
[color=Black]y2 [/color][color=DarkCyan]= [/color][color=Navy]3[/color]

[color=Blue]if [/color][color=Black]x1 [/color][color=DarkCyan]< [/color][color=Black]x2 [/color][color=Blue]then [/color][color=Black]: sx [/color][color=DarkCyan]= [/color][color=Navy]1 [/color][color=Black]: dx [/color][color=DarkCyan]= [/color][color=Black]x2 [/color][color=DarkCyan]- [/color][color=Black]x1 : [/color][color=Blue]else [/color][color=Black]sx [/color][color=DarkCyan]= -[/color][color=Navy]1 [/color][color=Black]: dx [/color][color=DarkCyan]= [/color][color=Black]x1 [/color][color=DarkCyan]- [/color][color=Black]x2 : [/color][color=Blue]endif
if [/color][color=Black]y1 [/color][color=DarkCyan]< [/color][color=Black]y2 [/color][color=Blue]then [/color][color=Black]: sy [/color][color=DarkCyan]= [/color][color=Navy]1 [/color][color=Black]: dy [/color][color=DarkCyan]= [/color][color=Black]y2 [/color][color=DarkCyan]- [/color][color=Black]y1 : [/color][color=Blue]else [/color][color=Black]sy [/color][color=DarkCyan]= -[/color][color=Navy]1 [/color][color=Black]: dy [/color][color=DarkCyan]= [/color][color=Black]y1 [/color][color=DarkCyan]- [/color][color=Black]y2 : [/color][color=Blue]endif
if [/color][color=Black]dx [/color][color=DarkCyan]> [/color][color=Black]dy [/color][color=Blue]then [/color][color=Black]: er [/color][color=DarkCyan]= [/color][color=Black]dx : [/color][color=Blue]else [/color][color=Black]er [/color][color=DarkCyan]= [/color][color=Black]dy : [/color][color=Blue]endif [/color][color=Green]; Don't divide "er" by 2[/color]

[color=Blue]if [/color][color=Black]dx [/color][color=DarkCyan]> [/color][color=Black]dy [/color][color=Blue]then
      do
            call [/color][color=Black]plot
            [/color][color=Blue]if [/color][color=Black]x1 [/color][color=DarkCyan]= [/color][color=Black]x2 [/color][color=DarkCyan]and [/color][color=Black]y1 [/color][color=DarkCyan]= [/color][color=Black]y2 [/color][color=Blue]then exit    [/color][color=Green]; Or return from subroutine
            [/color][color=Black]x1 [/color][color=DarkCyan]= [/color][color=Black]x1 [/color][color=DarkCyan]+ [/color][color=Black]sx : er [/color][color=DarkCyan]= [/color][color=Black]er [/color][color=DarkCyan]- [/color][color=Black]dy [/color][color=DarkCyan]- [/color][color=Black]dy    [/color][color=Green]; Subtract twice as "er" is doubled
            [/color][color=Blue]if [/color][color=Black]er [/color][color=DarkCyan]> [/color][color=Black]maxpos [/color][color=Blue]then [/color][color=Green]; It's Negative
                  [/color][color=Black]er [/color][color=DarkCyan]= [/color][color=Black]er [/color][color=DarkCyan]+ [/color][color=Black]dx [/color][color=DarkCyan]+ [/color][color=Black]dx : y1 [/color][color=DarkCyan]= [/color][color=Black]y1 [/color][color=DarkCyan]+ [/color][color=Black]sy 
            [/color][color=Blue]endif 
      loop  
      
      
      
else
      do
            call [/color][color=Black]plot
            [/color][color=Blue]if [/color][color=Black]x1 [/color][color=DarkCyan]= [/color][color=Black]x2 [/color][color=DarkCyan]and [/color][color=Black]y1 [/color][color=DarkCyan]= [/color][color=Black]y2 [/color][color=Blue]then exit    [/color][color=Green]; Or return from subroutine
            [/color][color=Black]y1 [/color][color=DarkCyan]= [/color][color=Black]y1 [/color][color=DarkCyan]+ [/color][color=Black]sy : er [/color][color=DarkCyan]= [/color][color=Black]er [/color][color=DarkCyan]- [/color][color=Black]dx [/color][color=DarkCyan]- [/color][color=Black]dx
            [/color][color=Blue]if [/color][color=Black]er [/color][color=DarkCyan]> [/color][color=Black]maxpos [/color][color=Blue]then 
                  [/color][color=Black]er [/color][color=DarkCyan]= [/color][color=Black]er [/color][color=DarkCyan]+ [/color][color=Black]dy [/color][color=DarkCyan]+ [/color][color=Black]dy : x1 [/color][color=DarkCyan]= [/color][color=Black]x1 [/color][color=DarkCyan]+ [/color][color=Black]sx
            [/color][color=Blue]endif
      loop
endif
end[/color]

[color=Black]plot:
      [/color][color=Blue]sertxd(cr[/color][color=Black],#x1,[/color][color=Red]" "[/color][color=Black],#y1[/color][color=Blue])
return[/color]
I also suggest not using a call for plotting, but direct insertion of code (2 times) or using a macro.
 

BESQUEUT

Senior Member
Hi Besqeuet, there is no px,py calc for the call plot routine?? That's the difficult part.
I have only optimised #21 code, supposing it is working...


Seems to work well in the simulator. What are px, py ?
As writen by Allycat, X1, Y1 are destroyed and used for plot values.
New version with macro :
Rich (BB code):
REM === DRAW a LINE. Ported from BBC Basic version. AllyCat December 2016.
REM Inputs are X1, Y1, X2, Y2: Destroys value of X1, Y1
REM JYB optimised

#picaxe 08m2 ; And almost any other
symbol x1 = b1
symbol x2 = b2
symbol y1 = b3 
symbol y2 = b4
symbol dx = b5
symbol dy = b6
symbol sx = b7
symbol sy = b8
symbol er = w9 
symbol maxpos = $7fff

#macro Plot(pX,pY)
      sertxd(cr,#pX," ",#pY)
      if x1 = x2 and y1 = y2 then exit    ; Or return from subroutine
#endmacro

x1 = 0 ; Test data
y1 = 10
x2 = 10
y2 = 3

if x1 < x2 then : sx = 1 : dx = x2 - x1 : else sx = -1 : dx = x1 - x2 : endif
if y1 < y2 then : sy = 1 : dy = y2 - y1 : else sy = -1 : dy = y1 - y2 : endif
if dx > dy then : er = dx : else er = dy : endif ; Don't divide "er" by 2

if dx > dy then
      do
            plot(X1,Y1)
            x1 = x1 + sx : er = er - dy - dy    ; Subtract twice as "er" is doubled
            if er > maxpos then ; It's Negative
                  er = er + dx + dx : y1 = y1 + sy 
            endif 
      loop  
      
      
      
else
      do
            plot(X1,Y1)
            y1 = y1 + sy : er = er - dx - dx
            if er > maxpos then 
                  er = er + dy + dy : x1 = x1 + sx
            endif
      loop
endif
end
 
Last edited:

AllyCat

Senior Member
Hi,

If you're concerned about speed then you could also precalculate dx * 2 and dy * 2. IIRC, when I measured typical execution times (of var1 = var1 + var2 versus var1 = var1 + var2 + var3), I was surprised how much the extra component extended the execution time (maybe the PE compiler splits it into two separate commands). They might then need to be word variables but that doesn't affect the execution speed significantly.

IMHO putting the "exit" test in the Macro is a bad idea. In the "dx > dy" section it's only necessary to test for x1 = x2 and similarly only y1 = y2 in the "else" section.

But the major speed improvement is removing the CALL (or more specifically its RETURN). I only added it at the last moment for clarity (as the SERTXD was only for testing) , but I would always normally put any such code in-line.

Cheers, Alan.
 

Technical

Technical Support
Staff member
The firmware/compiler has an optimisation where 'var1 = var1 + var2' is processed internally as 'var1 += var2'. However that optimistation cannot be used in the firmware when there are multiple components (var1 = var1+ var2 + var3), so that calculation takes longer.

In effect it is 'add var2 into var1' or 'add var1 to var2 to var3 then put answer in var1'
 

BESQUEUT

Senior Member
But the major speed improvement is removing the CALL (or more specifically its RETURN). I only added it at the last moment for clarity (as the SERTXD was only for testing) , but I would always normally put any such code in-line.

Cheers, Alan.
Writing code in-line or using à macro is the same thing.

New code whit Allycat and Technical improvements :
Rich (BB code):
REM === DRAW a LINE. Ported from BBC Basic version. AllyCat December 2016.
REM Inputs are X1, Y1, X2, Y2: Destroys value of X1, Y1
REM JYB optimised

#picaxe 08m2 ; And almost any other
symbol x1 = b1
symbol x2 = b2
symbol y1 = b3 
symbol y2 = b4
symbol x = b5
symbol y = b6
symbol sx = b7
symbol sy = b8
symbol dx = w7
symbol dy = w8
symbol er = w9 
symbol maxpos = $7fff

#macro Plot(pX,pY)
      sertxd(cr,#pX," ",#pY)

#endmacro

x1 = 0 ; Test data
y1 = 10
x2 = 10
y2 = 3

if x1 < x2 then : sx = 1 : dx = x2 - x1 : else sx = -1 : dx = x1 - x2 : endif
if y1 < y2 then : sy = 1 : dy = y2 - y1 : else sy = -1 : dy = y1 - y2 : endif
if dx > dy then : er = dx : else er = dy : endif ; Don't divide "er" by 2
dx =dx+dx : dy =dy+dy

if dx > dy then
      do
            plot(X1,Y1)
            if x1 = x2 then exit    ; Or return from subroutine
            x1 = x1 + sx : er = er - dy
            if er > maxpos then ; It's Negative
                  er = er + dx  : y1 = y1 + sy 
            endif 
      loop  
      
      
      
else
      do
            plot(X1,Y1)
            if y1 = y2 then exit    ; Or return from subroutine
            y1 = y1 + sy : er = er - dx 
            if er > maxpos then 
                  er = er + dy : x1 = x1 + sx
            endif
      loop
endif
end
 
Last edited:

BESQUEUT

Senior Member
Another version, maybe faster :
Rich (BB code):
REM === DRAW a LINE. Ported from BBC Basic version. AllyCat December 2016.
REM Inputs are X1, Y1, X2, Y2: 
REM Does not destroys values of X1, Y1
REM JYB optimised

#picaxe 08m2 ; And almost any other
symbol x1 = b1
symbol x2 = b2
symbol y1 = b3 
symbol y2 = b4
symbol X = b5
symbol Y = b6
symbol sx = b7
symbol sy = b8
symbol dx = w7
symbol dy = w8
symbol er = w9 
symbol maxpos = $7fff

#macro Plot(pX,pY)
      sertxd(cr,#pX," ",#pY)
#endmacro

x1 = 0 ; Test data
y1 = 10
x2 = 10
y2 = 3

if x1 < x2 then : sx = 1 : dx = x2 - x1 : else sx = -1 : dx = x1 - x2 : endif
if y1 < y2 then : sy = 1 : dy = y2 - y1 : else sy = -1 : dy = y1 - y2 : endif
if dx > dy then : er = dx : else er = dy : endif ; Don't divide "er" by 2
dx =dx+dx : dy =dy+dy

if dx > dy then
      y=y1
      for X=x1 to x2 step sx
            plot(X,Y)
            er = er - dy
            if er > maxpos then ; It's Negative
                  er = er + dx  : y = y + sy 
            endif 
      next X
      
else
      x=x1
      for Y=y1 to y2 step sy
            plot(X,Y)
            er = er - dx 
            if er > maxpos then 
                  er = er + dy : x = x + sx
            endif
      next Y
endif
end
 
Last edited by a moderator:

hippy

Technical Support
Staff member
if er > maxpos then ; It's Negative

If 'er' is symbol defined as 'w0' then that can be optimised to the faster ...

if bit15 = 1 then ; It's Negative
 

AllyCat

Senior Member
Hi,

Another version, maybe faster :
Yes that's (almost) what I tested last night, or even:

Code:
; ...
X = x1 : Y = y1     ; Only required to retain initial data

if dx > dy then
      for x1 = x1 to x2 step sx
            plot(x1,y1)
;  etc..
But I'm not convinced that having two instances of the PLOT routine is necessarily a good idea. It might be too large to justify repetition in-line (by whatever method that is done) and a subroutine CALL adds much more time delay than any potential savings.

Cheers, Alan.
 

hippy

Technical Support
Staff member
But I'm not convinced that having two instances of the PLOT routine is necessarily a good idea.
This is always the uncertainty in optimisation; which option is best.

By having 'sx' and 'sy' one can avoid the IF test I have in my code. That's faster but needs more variables and may mean slightly more code for initialising both. By swapping the line end points one can avoid having 'x' or 'y' decrementing. Whether the step is along the X or Y axis can be handled within the loop or outside with two loops. Each has its pro's and con's, each will save some speed or memory in one respect but can add in others. Speed and size are usually inverse to each other.

Ultimately there's often little to do to determine which is best other than to try them and measure the results. And if limitations force one's hand towards one solution over another then that's what one has to chose.
 

AllyCat

Senior Member
Hi,

If 'er' is symbol defined as 'w0' then that can be optimised to the faster ... if bit15 = 1
Yes, that saves about 250 (PIC) Instruction Cycles (250us @ 4MHz), but it wouldn't be worth copying "er" to w0 (which takes about 550 Instruction cycles) to test the bit. I don't have code/hardware to test an X2, but I bet IF er BIT 15 SET takes longer. ;)

However, this rather pales into insignificance compared with a CALL .. RETURN that takes 3,250 ICs or even a SWAP at 2,850 ICs. And of course the "PLOT" SERTXD at 4800 baud takes around 15,000+ ICs.

Cheers, Alan.
 

BESQUEUT

Senior Member
This is always the uncertainty in optimisation; which option is best.

By having 'sx' and 'sy' one can avoid the IF test I have in my code. That's faster but needs more variables and may mean slightly more code for initialising both. By swapping the line end points one can avoid having 'x' or 'y' decrementing. Whether the step is along the X or Y axis can be handled within the loop or outside with two loops. Each has its pro's and con's, each will save some speed or memory in one respect but can add in others. Speed and size are usually inverse to each other.

Ultimately there's often little to do to determine which is best other than to try them and measure the results. And if limitations force one's hand towards one solution over another then that's what one has to chose.
As long as it fit in memory, there is no need to optimize size...
Usually, drawing code needs to be as fast as possible...
 

stan74

Senior Member
The code by Alan and modified by BESQUEUT will not draw lines with ystart > Yend and xstart > xend will not draw vertical line..for x= 0 to 0 whwere xstart=xend and not lines where yend-ystart/xend-xstart >=1..see photo.
If xstart>xend or ystart>yend then ...I tried swap x1,x2 and tried for x=x2 to x1 step -sx but no joy.SAM_1236.JPG
 

AllyCat

Senior Member
Hi,

Yes it appears that STEP is not permitted to be a (negative) variable. The command syntax is a little vague but specifies that the variable, start and end are "variables" but the step is a "value". It also says "If Increment is preceded by a '-'," not "If Increment has a negative value". I think it may also have mistakenly printed "of" for "or".

So back to my original IF .. THEN loop structure which can be almost as efficient (just a few hundred Instruction Cycles more per pass).

Cheers, Alan.
 

stan74

Senior Member
This code will draw in any direction but this misses the vertical line on the left side of the screen with this demo.top left is 0,0 bottom right is 127,63
let x1=127:let y1=63:let y2=0
for x2=0 to 127 step 16
let y1=63
let x1=127
gosub line
next x2
;
Rich (BB code):
line:
if x1 < x2 then :let sx = 1 :let dx = x2 - x1:else let sx = -1 :let dx = x1 - x2 : endif
if y1 < y2 then :let sy = 1 :let dy = y2 - y1:else let sy = -1 :let dy = y1 - y2 : endif
if dx > dy then :let er = dx:else let er = dy : endif ; Don't divide "er" by 2
let dx =dx+dx :let dy =dy+dy

if dx > dy then
      let py=y1
      if x1<x2 then
      for px=x1 to x2
            gosub plot 
            let er = er - dy
            if er > maxpos then ; It's Negative
                  let er = er + dx:let py = py + sy 
            endif 
      next px
      else
      for px=x1 to x2 step-1
            gosub plot 
            let er = er - dy
            if er > maxpos then ; It's Negative
                  let er = er + dx:let py = py + sy
            endif
      next px
      endif
else
      let px=x1
      if y1<y2 then
            for py=y1 to y2
                  gosub plot
                  let er = er - dx
                  if er > maxpos then
                        let er = er + dy:let px = px + sx
                  endif
            next py
      else        
            for py=y1 to y2 step-1
                  gosub plot
                  let er = er - dx 
                  if er > maxpos then
                        let er = er + dy:let px = px + sx
                  endif
            next py
      endif
endif
return
Strange for px=x1 to x2 step-1 works but for px=x2 to x1 doesn't.
 

BESQUEUT

Senior Member
Hi,

Yes it appears that STEP is not permitted to be a (negative) variable. The command syntax is a little vague but specifies that the variable, start and end are "variables" but the step is a "value". It also says "If Increment is preceded by a '-'," not "If Increment has a negative value". I think it may also have mistakenly printed "of" for "or".

So back to my original IF .. THEN loop structure which can be almost as efficient (just a few hundred Instruction Cycles more per pass).

Cheers, Alan.
Code:
[color=Green]REM === DRAW a LINE. Ported from BBC Basic version. AllyCat December 2016.
REM Inputs are X1, Y1, X2, Y2: 
REM Does not destroys values of X1, Y1
REM JYB optimised[/color]
[color=Navy]#simspeed 20
#picaxe [/color][color=Black]08m2 [/color][color=Green]; And almost any other[/color]
[color=Blue]symbol [/color][color=Purple]x1 [/color][color=DarkCyan]= [/color][color=Purple]b1[/color]
[color=Blue]symbol [/color][color=Purple]x2 [/color][color=DarkCyan]= [/color][color=Purple]b2[/color]
[color=Blue]symbol [/color][color=Purple]y1 [/color][color=DarkCyan]= [/color][color=Purple]b3 [/color]
[color=Blue]symbol [/color][color=Purple]y2 [/color][color=DarkCyan]= [/color][color=Purple]b4[/color]
[color=Blue]symbol [/color][color=Purple]X [/color][color=DarkCyan]= [/color][color=Purple]b5[/color]
[color=Blue]symbol [/color][color=Purple]Y [/color][color=DarkCyan]= [/color][color=Purple]b6[/color]
[color=Blue]symbol [/color][color=Purple]sx [/color][color=DarkCyan]= [/color][color=Purple]b7[/color]
[color=Blue]symbol [/color][color=Purple]sy [/color][color=DarkCyan]= [/color][color=Purple]b8[/color]
[color=Blue]symbol [/color][color=Purple]dx [/color][color=DarkCyan]= [/color][color=Purple]w7[/color]
[color=Blue]symbol [/color][color=Purple]dy [/color][color=DarkCyan]= [/color][color=Purple]w8[/color]
[color=Blue]symbol [/color][color=Purple]er [/color][color=DarkCyan]= [/color][color=Purple]w9 [/color]
[color=Blue]symbol maxpos [/color][color=DarkCyan]= [/color][color=Navy]$7fff

#macro [/color][color=Black]Plot[/color][color=Blue]([/color][color=Black]pX,pY[/color][color=Blue])
      sertxd([/color][color=Black]#pX,[/color][color=Red]" "[/color][color=Black],#pY,[/color][color=Blue]cr)[/color]
[color=Navy]#endmacro

#macro [/color][color=Black]DrawLine[/color][color=Blue]([/color][color=Black]XX1,YY1,XX2,YY2[/color][color=Blue])
      [/color][color=Purple]x1 [/color][color=DarkCyan]=[/color][color=Black]xx1
      [/color][color=Purple]y1 [/color][color=DarkCyan]= [/color][color=Black]yy1
      [/color][color=Purple]x2 [/color][color=DarkCyan]= [/color][color=Black]xx2
      [/color][color=Purple]y2 [/color][color=DarkCyan]= [/color][color=Black]yy2
      [/color][color=Blue]GOSUB [/color][color=Black]Line[/color]
[color=Navy]#endmacro[/color]

[color=Black]DrawLine[/color][color=Blue]([/color][color=Navy]0[/color][color=Black],[/color][color=Navy]10[/color][color=Black],[/color][color=Navy]10[/color][color=Black],[/color][color=Navy]3[/color][color=Blue])[/color]
[color=Black]DrawLine[/color][color=Blue]([/color][color=Navy]10[/color][color=Black],[/color][color=Navy]10[/color][color=Black],[/color][color=Navy]0[/color][color=Black],[/color][color=Navy]3[/color][color=Blue])[/color]
[color=Black]DrawLine[/color][color=Blue]([/color][color=Navy]10[/color][color=Black],[/color][color=Navy]12[/color][color=Black],[/color][color=Navy]10[/color][color=Black],[/color][color=Navy]3[/color][color=Blue])[/color]
[color=Black]DrawLine[/color][color=Blue]([/color][color=Navy]10[/color][color=Black],[/color][color=Navy]3[/color][color=Black],[/color][color=Navy]0[/color][color=Black],[/color][color=Navy]3[/color][color=Blue])
end[/color]

[color=Black]Line:[/color]
[color=Blue]sertxd(cr[/color][color=Black],[/color][color=Blue]cr[/color][color=Black],#[/color][color=Purple]X1[/color][color=Black],[/color][color=Red]", "[/color][color=Black],#[/color][color=Purple]Y1[/color][color=Black],[/color][color=Red]" -- "[/color][color=Black],#[/color][color=Purple]X2[/color][color=Black],[/color][color=Red]", "[/color][color=Black],#[/color][color=Purple]Y2[/color][color=Black],[/color][color=Blue]cr)

if [/color][color=Purple]x1 [/color][color=DarkCyan]< [/color][color=Purple]x2 [/color][color=Blue]then [/color][color=Black]: [/color][color=Purple]sx [/color][color=DarkCyan]= [/color][color=Navy]1 [/color][color=Black]: [/color][color=Purple]dx [/color][color=DarkCyan]= [/color][color=Purple]x2 [/color][color=DarkCyan]- [/color][color=Purple]x1 [/color][color=Black]: [/color][color=Blue]else [/color][color=Purple]sx [/color][color=DarkCyan]= -[/color][color=Navy]1 [/color][color=Black]: [/color][color=Purple]dx [/color][color=DarkCyan]= [/color][color=Purple]x1 [/color][color=DarkCyan]- [/color][color=Purple]x2 [/color][color=Black]: [/color][color=Blue]endif
if [/color][color=Purple]y1 [/color][color=DarkCyan]< [/color][color=Purple]y2 [/color][color=Blue]then [/color][color=Black]: [/color][color=Purple]sy [/color][color=DarkCyan]= [/color][color=Navy]1 [/color][color=Black]: [/color][color=Purple]dy [/color][color=DarkCyan]= [/color][color=Purple]y2 [/color][color=DarkCyan]- [/color][color=Purple]y1 [/color][color=Black]: [/color][color=Blue]else [/color][color=Purple]sy [/color][color=DarkCyan]= -[/color][color=Navy]1 [/color][color=Black]: [/color][color=Purple]dy [/color][color=DarkCyan]= [/color][color=Purple]y1 [/color][color=DarkCyan]- [/color][color=Purple]y2 [/color][color=Black]: [/color][color=Blue]endif
if [/color][color=Purple]dx [/color][color=DarkCyan]> [/color][color=Purple]dy [/color][color=Blue]then [/color][color=Black]: [/color][color=Purple]er [/color][color=DarkCyan]= [/color][color=Purple]dx [/color][color=Black]: [/color][color=Blue]else [/color][color=Purple]er [/color][color=DarkCyan]= [/color][color=Purple]dy [/color][color=Black]: [/color][color=Blue]endif [/color][color=Green]; Don't divide "er" by 2[/color]
[color=Purple]dx [/color][color=DarkCyan]=[/color][color=Purple]dx[/color][color=DarkCyan]+[/color][color=Purple]dx [/color][color=Black]: [/color][color=Purple]dy [/color][color=DarkCyan]=[/color][color=Purple]dy[/color][color=DarkCyan]+[/color][color=Purple]dy[/color]

[color=Blue]if [/color][color=Purple]dx [/color][color=DarkCyan]> [/color][color=Purple]dy [/color][color=Blue]then
      do
            [/color][color=Black]plot[/color][color=Blue]([/color][color=Purple]X1[/color][color=Black],[/color][color=Purple]Y1[/color][color=Blue])
            if [/color][color=Purple]x1 [/color][color=DarkCyan]= [/color][color=Purple]x2 [/color][color=Blue]then exit    [/color][color=Green]; Or return from subroutine
            [/color][color=Purple]x1 [/color][color=DarkCyan]= [/color][color=Purple]x1 [/color][color=DarkCyan]+ [/color][color=Purple]sx [/color][color=Black]: [/color][color=Purple]er [/color][color=DarkCyan]= [/color][color=Purple]er [/color][color=DarkCyan]- [/color][color=Purple]dy
            [/color][color=Blue]if [/color][color=Purple]er [/color][color=DarkCyan]> [/color][color=Blue]maxpos then [/color][color=Green]; It's Negative
                  [/color][color=Purple]er [/color][color=DarkCyan]= [/color][color=Purple]er [/color][color=DarkCyan]+ [/color][color=Purple]dx  [/color][color=Black]: [/color][color=Purple]y1 [/color][color=DarkCyan]= [/color][color=Purple]y1 [/color][color=DarkCyan]+ [/color][color=Purple]sy 
            [/color][color=Blue]endif 
      loop  
      
      
      
else
      do
            [/color][color=Black]plot[/color][color=Blue]([/color][color=Purple]X1[/color][color=Black],[/color][color=Purple]Y1[/color][color=Blue])
            if [/color][color=Purple]y1 [/color][color=DarkCyan]= [/color][color=Purple]y2 [/color][color=Blue]then exit    [/color][color=Green]; Or return from subroutine
            [/color][color=Purple]y1 [/color][color=DarkCyan]= [/color][color=Purple]y1 [/color][color=DarkCyan]+ [/color][color=Purple]sy [/color][color=Black]: [/color][color=Purple]er [/color][color=DarkCyan]= [/color][color=Purple]er [/color][color=DarkCyan]- [/color][color=Purple]dx 
            [/color][color=Blue]if [/color][color=Purple]er [/color][color=DarkCyan]> [/color][color=Blue]maxpos then 
                  [/color][color=Purple]er [/color][color=DarkCyan]= [/color][color=Purple]er [/color][color=DarkCyan]+ [/color][color=Purple]dy [/color][color=Black]: [/color][color=Purple]x1 [/color][color=DarkCyan]= [/color][color=Purple]x1 [/color][color=DarkCyan]+ [/color][color=Purple]sx
            [/color][color=Blue]endif
      loop
endif
return[/color]
==>
Code:
0, 10 -- 10, 3
0 10
1 9
2 9
3 8
4 7
5 7
6 6
7 5
8 4
9 4
10 3


10, 10 -- 0, 3
10 10
9 9
8 9
7 8
6 7
5 7
4 6
3 5
2 4
1 4
0 3


10, 12 -- 10, 3
10 12
10 11
10 10
10 9
10 8
10 7
10 6
10 5
10 4
10 3


10, 3 -- 0, 3
10 3
9 3
8 3
7 3
6 3
5 3
4 3
3 3
2 3
1 3
0 3
This code will draw in any direction but this misses the vertical line on the left side of the screen with this demo.top left is 0,0 bottom right is 127,63
let x1=127:let y1=63:let y2=0
for x2=0 to 127 step 16
let y1=63
let x1=127
gosub line
next x2
As x1 is always 127, never 0, there cannot be a vertical line on left side..;
DrawLine(127,63,127,0)
DrawLine(0,63,0,0)
work well...

Stan : please publish whole code, not only extracts...
 
Last edited:

BESQUEUT

Senior Member
if er > maxpos then ; It's Negative

If 'er' is symbol defined as 'w0' then that can be optimised to the faster ...

if bit15 = 1 then ; It's Negative
Code:
[color=Green]REM === DRAW a LINE. Ported from BBC Basic version. AllyCat December 2016.
REM Inputs are X1, Y1, X2, Y2: 
REM Does not destroys values of X1, Y1
REM JYB and Hippy optimised[/color]

[color=Navy]#simspeed 20
#picaxe [/color][color=Black]08m2 [/color][color=Green]; And almost any other[/color]
[color=Blue]symbol [/color][color=Purple]x1 [/color][color=DarkCyan]= [/color][color=Purple]b3[/color]
[color=Blue]symbol [/color][color=Purple]x2 [/color][color=DarkCyan]= [/color][color=Purple]b4[/color]
[color=Blue]symbol [/color][color=Purple]y1 [/color][color=DarkCyan]= [/color][color=Purple]b5 [/color]
[color=Blue]symbol [/color][color=Purple]y2 [/color][color=DarkCyan]= [/color][color=Purple]b6[/color]

[color=Blue]symbol [/color][color=Purple]sx [/color][color=DarkCyan]= [/color][color=Purple]b7[/color]
[color=Blue]symbol [/color][color=Purple]sy [/color][color=DarkCyan]= [/color][color=Purple]b8[/color]
[color=Blue]symbol [/color][color=Purple]dx [/color][color=DarkCyan]= [/color][color=Purple]w7[/color]
[color=Blue]symbol [/color][color=Purple]dy [/color][color=DarkCyan]= [/color][color=Purple]w8[/color]
[color=Blue]symbol [/color][color=Purple]er [/color][color=DarkCyan]= [/color][color=Purple]w0 [/color]


[color=Navy]#macro [/color][color=Black]Plot[/color][color=Blue]([/color][color=Black]pX,pY[/color][color=Blue])
      sertxd([/color][color=Black]#pX,[/color][color=Red]" "[/color][color=Black],#pY,[/color][color=Blue]cr)[/color]
[color=Navy]#endmacro

#macro [/color][color=Black]DrawLine[/color][color=Blue]([/color][color=Black]XX1,YY1,XX2,YY2[/color][color=Blue])
      [/color][color=Purple]x1 [/color][color=DarkCyan]=[/color][color=Black]xx1
      [/color][color=Purple]y1 [/color][color=DarkCyan]= [/color][color=Black]yy1
      [/color][color=Purple]x2 [/color][color=DarkCyan]= [/color][color=Black]xx2
      [/color][color=Purple]y2 [/color][color=DarkCyan]= [/color][color=Black]yy2
      [/color][color=Blue]GOSUB [/color][color=Black]Line[/color]
[color=Navy]#endmacro[/color]

[color=Black]DrawLine[/color][color=Blue]([/color][color=Navy]0[/color][color=Black],[/color][color=Navy]10[/color][color=Black],[/color][color=Navy]10[/color][color=Black],[/color][color=Navy]3[/color][color=Blue])[/color]
[color=Black]DrawLine[/color][color=Blue]([/color][color=Navy]10[/color][color=Black],[/color][color=Navy]10[/color][color=Black],[/color][color=Navy]0[/color][color=Black],[/color][color=Navy]3[/color][color=Blue])[/color]
[color=Black]DrawLine[/color][color=Blue]([/color][color=Navy]10[/color][color=Black],[/color][color=Navy]12[/color][color=Black],[/color][color=Navy]10[/color][color=Black],[/color][color=Navy]3[/color][color=Blue])[/color]
[color=Black]DrawLine[/color][color=Blue]([/color][color=Navy]10[/color][color=Black],[/color][color=Navy]3[/color][color=Black],[/color][color=Navy]0[/color][color=Black],[/color][color=Navy]3[/color][color=Blue])[/color]

[color=Green]'DrawLine(127,63,127,0)
'DrawLine(0,63,0,0)[/color]
[color=Blue]end[/color]

[color=Black]Line:[/color]
[color=Blue]sertxd(cr[/color][color=Black],[/color][color=Blue]cr[/color][color=Black],#[/color][color=Purple]X1[/color][color=Black],[/color][color=Red]", "[/color][color=Black],#[/color][color=Purple]Y1[/color][color=Black],[/color][color=Red]" -- "[/color][color=Black],#[/color][color=Purple]X2[/color][color=Black],[/color][color=Red]", "[/color][color=Black],#[/color][color=Purple]Y2[/color][color=Black],[/color][color=Blue]cr)

if [/color][color=Purple]x1 [/color][color=DarkCyan]< [/color][color=Purple]x2 [/color][color=Blue]then [/color][color=Black]: [/color][color=Purple]sx [/color][color=DarkCyan]= [/color][color=Navy]1 [/color][color=Black]: [/color][color=Purple]dx [/color][color=DarkCyan]= [/color][color=Purple]x2 [/color][color=DarkCyan]- [/color][color=Purple]x1 [/color][color=Black]: [/color][color=Blue]else [/color][color=Purple]sx [/color][color=DarkCyan]= -[/color][color=Navy]1 [/color][color=Black]: [/color][color=Purple]dx [/color][color=DarkCyan]= [/color][color=Purple]x1 [/color][color=DarkCyan]- [/color][color=Purple]x2 [/color][color=Black]: [/color][color=Blue]endif
if [/color][color=Purple]y1 [/color][color=DarkCyan]< [/color][color=Purple]y2 [/color][color=Blue]then [/color][color=Black]: [/color][color=Purple]sy [/color][color=DarkCyan]= [/color][color=Navy]1 [/color][color=Black]: [/color][color=Purple]dy [/color][color=DarkCyan]= [/color][color=Purple]y2 [/color][color=DarkCyan]- [/color][color=Purple]y1 [/color][color=Black]: [/color][color=Blue]else [/color][color=Purple]sy [/color][color=DarkCyan]= -[/color][color=Navy]1 [/color][color=Black]: [/color][color=Purple]dy [/color][color=DarkCyan]= [/color][color=Purple]y1 [/color][color=DarkCyan]- [/color][color=Purple]y2 [/color][color=Black]: [/color][color=Blue]endif
if [/color][color=Purple]dx [/color][color=DarkCyan]> [/color][color=Purple]dy [/color][color=Blue]then [/color][color=Black]: [/color][color=Purple]er [/color][color=DarkCyan]= [/color][color=Purple]dx [/color][color=Black]: [/color][color=Blue]else [/color][color=Purple]er [/color][color=DarkCyan]= [/color][color=Purple]dy [/color][color=Black]: [/color][color=Blue]endif [/color][color=Green]; Don't divide "er" by 2[/color]
[color=Purple]dx [/color][color=DarkCyan]=[/color][color=Purple]dx[/color][color=DarkCyan]+[/color][color=Purple]dx [/color][color=Black]: [/color][color=Purple]dy [/color][color=DarkCyan]=[/color][color=Purple]dy[/color][color=DarkCyan]+[/color][color=Purple]dy[/color]

[color=Blue]if [/color][color=Purple]dx [/color][color=DarkCyan]> [/color][color=Purple]dy [/color][color=Blue]then
      do
            [/color][color=Black]plot[/color][color=Blue]([/color][color=Purple]X1[/color][color=Black],[/color][color=Purple]Y1[/color][color=Blue])
            if [/color][color=Purple]x1 [/color][color=DarkCyan]= [/color][color=Purple]x2 [/color][color=Blue]then exit    [/color][color=Green]; Or return from subroutine
            [/color][color=Purple]x1 [/color][color=DarkCyan]= [/color][color=Purple]x1 [/color][color=DarkCyan]+ [/color][color=Purple]sx [/color][color=Black]: [/color][color=Purple]er [/color][color=DarkCyan]= [/color][color=Purple]er [/color][color=DarkCyan]- [/color][color=Purple]dy
            [/color][color=Blue]if [/color][color=Purple]bit15[/color][color=DarkCyan]=[/color][color=Navy]1 [/color][color=Blue]then [/color][color=Green]; It's Negative
                  [/color][color=Purple]er [/color][color=DarkCyan]= [/color][color=Purple]er [/color][color=DarkCyan]+ [/color][color=Purple]dx  [/color][color=Black]: [/color][color=Purple]y1 [/color][color=DarkCyan]= [/color][color=Purple]y1 [/color][color=DarkCyan]+ [/color][color=Purple]sy 
            [/color][color=Blue]endif 
      loop  
      
      
      
else
      do
            [/color][color=Black]plot[/color][color=Blue]([/color][color=Purple]X1[/color][color=Black],[/color][color=Purple]Y1[/color][color=Blue])
            if [/color][color=Purple]y1 [/color][color=DarkCyan]= [/color][color=Purple]y2 [/color][color=Blue]then exit    [/color][color=Green]; Or return from subroutine
            [/color][color=Purple]y1 [/color][color=DarkCyan]= [/color][color=Purple]y1 [/color][color=DarkCyan]+ [/color][color=Purple]sy [/color][color=Black]: [/color][color=Purple]er [/color][color=DarkCyan]= [/color][color=Purple]er [/color][color=DarkCyan]- [/color][color=Purple]dx 
            [/color][color=Blue]if [/color][color=Purple]bit15[/color][color=DarkCyan]=[/color][color=Navy]1 [/color][color=Blue]then 
                  [/color][color=Purple]er [/color][color=DarkCyan]= [/color][color=Purple]er [/color][color=DarkCyan]+ [/color][color=Purple]dy [/color][color=Black]: [/color][color=Purple]x1 [/color][color=DarkCyan]= [/color][color=Purple]x1 [/color][color=DarkCyan]+ [/color][color=Purple]sx
            [/color][color=Blue]endif
      loop
endif
return[/color]
Improvement to be measured with real Picaxe...
 

hippy

Technical Support
Staff member
Yes it appears that STEP is not permitted to be a (negative) variable.
The PICAXE has no concept of negative values; all it knows about is positive integers.

"FOR ... STEP n" will increase the index variable value by n.

"FOR ... STEP -n" will decrease the index variable value by n.

I haven't tested it but "STEP $FFFF" will probably decrease the index variable by one, be the equivalent of "STEP -1".
 
Top