# Drawing Arcs - Hewlett Packard

This is a discussion on Drawing Arcs - Hewlett Packard ; Thanks for the code, Cyrille It seems we had a similar idea, as i started too with a simple Full Circle algorithm, in order to provide some "training ground" for arc (Circle are simpler, there is no need to check ...

1. ## Re: Drawing Arcs

Thanks for the code, Cyrille

It seems we had a similar idea, as i started too with a simple Full
Circle algorithm,
in order to provide some "training ground" for arc
(Circle are simpler, there is no need to check bearing, just draw the
pixel).

Anyway, the goal being to learn, it's always good to be able to
compare.
It seems your code is using a different syntax than SASM, probably
MASD.
I read here and then that MASD syntax is more powerfull than SASM,
but for the time being, i'm not even able to compile such a piece of
code using Debug4x.
Could you give me a hint at how to do that ?

Anyway, for those interested, here are some results for the current
Full Circle algorithm, using an HP48SX :
FastCircle on HP48X :
30 pixels radius (65,30,30) ===> 0.24s
60 pixels radius (30,-10,60) ==> 0.31s

This is a first try, so it most probably can be optimized more.
But it was very usefull in helping to understand how to write ASM
Code, and especilly how to initialise graphic area, write pixels, and
so on.

This implementation allows center outside of screen (including
negative numbers), and radius up to 1000 pixels.

The ASM code can draw circles on any Grob of any size.
However, the herebelow proposed binary has a SysRPL header, which
checks arguments, and provide the Graphic Grob as an input to ASM.
Therefore, the circle is drawn in the Graphic Area, visible using
GRAPH command (or LEFT arrow).
A nice side effect is that it should support both 64 & 80 lines
systems without any problem.
And if Graphic Area is "larger than screen", it will make use of its
full size.

Binaries for both HP48 & HP49/50 are available here :
FastCircle V1.0 is 411 Bytes long.

Code is in english, but comment are written in french, though....

Cyrille, i tried to compare both source code, but still lack some
experience to properly understand MASD.
It seems your code is much more ambitious, as it can provide GreyScale
output.
You're welcomed for any comment.

OK, now for the more complex arc algorithm...

Regards

2. ## Re: Drawing Arcs

Hello Jacob

Here is a first try at an ASM Arc Algorithm :
http://img21.xooimage.com/files/8/6/...1.0-570f4c.zip

I've called it Fast Approximative Arc, because it can be wrong by one
pixel.
As i was not smart enough to properly understand how you did to check
if a pixel must be drawn,
i tried to invent an "homebrew" algorithm, based on circumference
length
(The most famous : Circ = 2 x Pi x R).
Well, on paper, it looks pretty and simple, but it comes with problems
of its own, especially estimating distance from a trail of pixel and
correcting cumulated error from the "real" circle.

As a consequence, this version is not directly comparable with yours.
I would appreciate if you could give me a hand at understanding how
you test [pixel within arc], this way it would be possible to create a
code which use the same algorithm, remaining differences only coming
from programming language.

Well, nonetheless, i'm providing binaries for this version, because it
can still usefull for comparison in the future.
Input is as follows : X0, Y0, Radius (in pixel), StartBearing,
EndBearing (in degree, with 0° being North).
As approximation error increases with Radius, this version limits R to
60 max.

Here are some performance results, from an HP48SX (i expect later
model to perform better) :
Full : 0.50s
Half : 0.29s
Quarter : 0.18s
Eight : 0.12s
1° : 0.07s (Note : 0° means "Full Circle", so cannot be tested)

3. ## Re: Drawing Arcs

On Aug 7, 6:32*am, Yann wrote:
> Hello Jacob
>
> Here is a first try at an ASM Arc Algorithm :http://img21.xooimage.com/files/8/6/...e-arc-v1.0-570...
>
> I've called it Fast Approximative Arc, because it can be wrong by one
> pixel.
> As i was not smart enough to properly understand how you did to check
> if a pixel must be drawn,
> i tried to invent an "homebrew" algorithm, based on circumference
> length
> (The most famous : Circ = 2 x Pi x R).
> Well, on paper, it looks pretty and simple, but it comes with problems
> of its own, especially estimating distance from a trail of pixel and
> correcting cumulated error from the "real" circle.
>
> As a consequence, this version is not directly comparable with yours.
> I would appreciate if you could give me a hand at understanding how
> you test [pixel within arc], this way it would be possible to create a
> code which use the same algorithm, remaining differences only coming
> from programming language.
>
> Well, nonetheless, i'm providing binaries for this version, because it
> can still usefull for comparison in the future.
> Input is as follows : X0, Y0, Radius (in pixel), StartBearing,
> EndBearing (in degree, with 0° being North).
> As approximation error increases with Radius, this version limits R to
> 60 max.
>
> Here are some performance results, from an HP48SX (i expect later
> model to perform better) :
> Full : 0.50s
> Half : 0.29s
> Quarter : 0.18s
> Eight : 0.12s
> 1° * *: 0.07s *(Note : 0° means "Full Circle", so cannot be tested)

Hello Yann,

I'll repost the program I came up with and put some explanatory notes
in along with the code to try and explain it. This is something I am
not very good at, but should get in the habit of doing regardless. So
here goes from the top:

::
CK5NOLASTWD
DOCLLCD
5ROLL
5ROLL
COERCE2
5UNROLL
5UNROLL
DUP
COERCE
%1
3PICK
%-
BINT0
DUP
5ROLL
DUP
%*
%2
%/
%SQRT
COERCE
BINT2
{}N
BINT8
NDUPN
DROP
NULLLAM
BINT15
NDUPN
DOBIND

***// This is preparing the input for the program and ends up being:
LAM 1 - LAM 8 are all lists of {MIN MAX} pixel in x (or y) direction
and by default I declare all 8 octants as being MIN= BINT0 and MAX=
(square root of half the radius squared), meaning the full octant
would be drawn if not otherwise interfered
LAM 9 = x to be used in bresenham loop, intially BINT0
LAM 10 = d to be used in bresenham loop, intially 1-radius
LAM 12 = bearing to end of arc, clockwise from North (as a surveyor
this makes more sense to me)
LAM 13 = bearing to beginning of arc
LAM 14 = Y0, y pixel coordinate of arc center
LAM 15 = X0, x pixel coordinate of arc center
//***

11GETLAM
UNCOERCE
12GETLAM
%POL>%REC
%ABS
SWAP
%ABS
SWAP
COERCE2
12GETLAM
COERCE

***//The above calculates the delta pixel in x and y directions from
center to the end of the arc by using the polar to rectangular %POL>
%REC and leaves in the stack:
3: deltay (Absolute) from center of arc to pixel that defines the end
of the arc as a BINT
2: deltax, same as above
1: bearing to end of arc
NOTE: because my program was designed to be intuitive for myself to
handle compass bearings, the x and y values will be switched later on,
conveniently if you swap x and y rectangular values you can use %REC>
%POL and get compass bearings, but that is really another topic
//***

11GETLAM
UNCOERCE
13GETLAM
%POL>%REC
%ABS
SWAP
%ABS
SWAP
COERCE2
13GETLAM
COERCE

***//This does the same as before except for the beginning of the arc
so now we have 6 values in the stack:
6: deltay (Absolute) from center of arc to pixel that defines the end
of the arc as a BINT
5: deltax, same as above BINT
4: bearing to end of arc BINT
3: deltay (Absolute) from center of arc to pixel that defines the
beginning of the arc as a BINT
2: deltax, same as above BINT
1: bearing to beginning of arc BINT
//***

BINT3
BINT1
DO
BINT9
BINT1
DO
DUP
BINT45
INDEX@
#*
#1+
#<
IT
::
DROP
INDEX@
::
DUP
BINT1
#=case
TrueTrue
DUP
BINT2
#=case
FalseFalse
DUP
BINT3
#=case
TrueFalse
DUP
BINT4
#=case
FALSETRUE
DUP
BINT5
#=case
TrueTrue
DUP
BINT6
#=case
FalseFalse
DUP
BINT7
#=case
TrueFalse
DUP
BINT8
#=case
FALSETRUE
;
ITE
::
4ROLL
DROP
;
::
ROT
DROP
;
ITE
::
SWAP
JINDEX@
INDEX@
GETLAM
PUTLIST
INDEX@
PUTLAM
;
::
SWAP
BINT3
JINDEX@
#-
INDEX@
GETLAM
PUTLIST
INDEX@
PUTLAM
;
DUP
BINT14
JINDEX@
#-
PUTLAM
ISTOPSTO
;
LOOP
LOOP

***//Ok, there's a number of things going on the 2 loops going on, the
"outer" loop first takes the bearing to first the beginning of arc in
the first pass, (then bearing to end of arc in second pass) and then
passes it to the "inner" loop to figure out which octant that bearing
falls in, once a match is made, 2 flags are generated that enable the
decisions whether for the corresponding arc, the bresenham loop is
increasing the x or the y values during each iteration and also if the
iterations proceed clockwise or counterclockwise, for example the
first octant if looking at it from north to 45 degrees clockwise uses
the x value as its going through the iterations and the direction is
clockwise, the second octant increases the y value and the iteration
goes counterclockwise. So basically the end product here is that for
the 2 octants, (or 1 octant) these two loops put the correct {MIN MAX}
values in the LAM1-LAM8 lists that will tell the bresenham loop
whether or not to draw the pixel during the iteration.
//***

13GETLAM
12GETLAM
#>
BINT9
BINT1
DO
DUP
INDEX@
12GETLAM
#>
INDEX@
13GETLAM
#<
ROT
ITE
AND
OR
IT
::
BINT0
INDEX@
PUTLAM
;
LOOP
DROP

***//This loop stores BINT0 into any octant LAMs that are not
contained in the arc, (which is not a list, and later a test is
performed to check if the corresponding LAM is a list or not
//***

BEGIN
::
10GETLAM
%0<
case
::
10GETLAM
9GETLAM
UNCOERCE
%2
%*
%3
%+
%+
10PUTLAM
;
::
10GETLAM
9GETLAM
UNCOERCE
%2
%*
11GETLAM
UNCOERCE
%2
%*
%-
%5
%+
%+
10PUTLAM
11GETLAM
#1-
11PUTLAM
;
;
1GETLAM
DUPTYPELIST?
ITE
::
INCOMPDROP
9GETLAM
#< NOT
SWAP
9GETLAM
#> NOT
AND
IT
::
15GETLAM
9GETLAM
#+
14GETLAM
11GETLAM
#-
PIXON
;
;
DROP
2GETLAM
DUPTYPELIST?
ITE
::
INCOMPDROP
9GETLAM
#< NOT
SWAP
9GETLAM
#> NOT
AND
IT
::
15GETLAM
11GETLAM
#+
14GETLAM
9GETLAM
#-
PIXON
;
;
DROP
3GETLAM
DUPTYPELIST?
ITE
::
INCOMPDROP
9GETLAM
#< NOT
SWAP
9GETLAM
#> NOT
AND
IT
::
15GETLAM
11GETLAM
#+
14GETLAM
9GETLAM
#+
PIXON
;
;
DROP
4GETLAM
DUPTYPELIST?
ITE
::
INCOMPDROP
9GETLAM
#< NOT
SWAP
9GETLAM
#> NOT
AND
IT
::
15GETLAM
9GETLAM
#+
14GETLAM
11GETLAM
#+
PIXON
;
;
DROP
5GETLAM
DUPTYPELIST?
ITE
::
INCOMPDROP
9GETLAM
#< NOT
SWAP
9GETLAM
#> NOT
AND
IT
::
15GETLAM
9GETLAM
#-
14GETLAM
11GETLAM
#+
PIXON
;
;
DROP
6GETLAM
DUPTYPELIST?
ITE
::
INCOMPDROP
9GETLAM
#< NOT
SWAP
9GETLAM
#> NOT
AND
IT
::
15GETLAM
11GETLAM
#-
14GETLAM
9GETLAM
#+
PIXON
;
;
DROP
7GETLAM
DUPTYPELIST?
ITE
::
INCOMPDROP
9GETLAM
#< NOT
SWAP
9GETLAM
#> NOT
AND
IT
::
15GETLAM
11GETLAM
#-
14GETLAM
9GETLAM
#-
PIXON
;
;
DROP
8GETLAM
DUPTYPELIST?
ITE
::
INCOMPDROP
9GETLAM
#< NOT
SWAP
9GETLAM
#> NOT
AND
IT
::
15GETLAM
9GETLAM
#-
14GETLAM
11GETLAM
#-
PIXON
;
;
DROP
9GETLAM
#1+
DUP
9PUTLAM
11GETLAM
#>
UNTIL

***//So that is the bresenham loop, and because the x and y values are
swapped (for surveyor piece of mind) you will find that even though
the algorithm is the same its simply set up differently to draw the
pixel I want it to. But for each octant it test if the pixel in
question during the iteration falls within the range that is {MIN MAX}
for that octant.
//***

ABND
SetDAsTemp
WaitForKey
2DROP
;
@

I hope this helps at least give the concept of what I was trying to
do. There are a number of different ways to attack this problem (and
Claudio seems to at least one more idea I still haven't had the time
to try out).

My program I should also modify to allow GRAD mode set, and a few
other tests to make it more universal...

Jacob

P.S. Thanks for the link to your binaries, Most likely a stupid
question, but when I run the program (with 5 reals in the stack, same
as the ones I was using or not?) I see only a blank screen, I did the
PICT RCL and saw only a blank grob, What am I doing wrong?

4. ## Re: Drawing Arcs

Thanks very much for these informations

Jacob,
i believe your explanations are quite clear. It should prove enough to
start again coding.
I just need to find a way to calculate end/begin x/y without relying
on RPL calls, should it be possible & efficient.

Ah, and regarding this first implementation of "approximative arc",
yes, there is a slight difference in the order of parameters compared
5 : X0
4 : Y0
2 : Beginning Arc (°)
1 : End Arc (°)

I've spent the last few days at improving the Circle algorithm,
because this is still a root source for Arc.
And the results are encouraging.

After getting rid of the previous "shift" methodology, i end up with
the following benchmarked results :
FastCircle V2
HP48SX
30 pixels (65,32,30) ==> 92ms
60 pixels (30,-10,60) ==> 98ms
200 pixels (60,215,200)==> 195ms

At this stage, FastCircle seems reasonably well optimised, and does
even compare favorably to Mark Power's Graph Library (http://
www.btinternet.com/~mark.power/hp48.htm) and any other assembler code
from HpCalc.org i could test. I've borrowed some ideas from Mark
Power's code by the end of development, which did not change
performance much (even slowed slightly by 1-2%), but help decrease the
code size.
As a consequence, FastCircle V2 is still 410 Bytes, although the
SysRPL header has increased quite a bit, due to a new feature : the
possibility to draw into any externally defined Grob (optional).

Input :
4 : Grob (Optional, if none provided, will draw into Graphic area)
3 : X0
2 : Y0
Notes :
(0,0) is upper left.
X0 & Y0 can be negative.
All values are limited to 1000 (Grob Width/Height, X, Y & Radius)

http://phantasie.tonempire.net/utili...circle-t58.htm

Cyrille, thank you for all these new inputs,
i will spend some time to digest everything, and try to make use of it
for the next step.
Some parts are still mysterious to me, especially the one where you
explain using a mask instead of a multiplication. well, that may be
because i'm tired after a pretty long trip today...

There are 2 directions which i believe can be investigated to improve
performances a bit more.

1) For drawn pixels, i'm using a hand-made multiplication, which is
faster than standard #MUL call?
For a standard 131 pixels width screen, it costs 163 cycles, instead
of 360 as before.
Quite an improvement, but it is still the most costly operation for a
drawn pixel.

Well, i find it quite a waste to do so many tests for each pixel,
whereas i know since initialisation one of the values, nibble-width.
For example, should i hard-code a fixed 131 pixels, which is 22h
nibbles, i would rather program :
"
C=C+C A
B=B+C A
CSL A
B=B+C A
"
That would be much much faster.

So, instead of running the full "generic" multiplication code, i've
ended up with the idea to actually produce the multiplication code at
initialisation. A kind of "tiny little brother" to modern concept such
as dynamic compilation.

I wonder if this can be considered on HP48, and what would be best way
to achieve this, if this is usefull.
The first idea was to replace the current space for multiplication by
a "writable" area, but that means self-modifying code, and does not
sounds good.
Another possibility would be to create a temporary object, in which
the multiplication code will be created, and link to it. Sure, GOSBVL/
RTN or PC manipulations are not cheap, but well, it should end up with
some interesting gain.
I currently wonder it that's actually an interesting idea.

2) For partial circles (out of area sections), especially for large
ones,
the discarding algorithm, although very much improved, still run on a
per-pixel basis.
I guess it *could* be faster to discard whole sections if it can be
easily calculated, at initialisation.
This is still to be investigated at this stage,
I have a simple idea in mind currently, based on squares,
but this is bound to increase code size, so i wonder if this is
actually worth it.

Please feel free to comment on any of these lines Cyrille. I think i
still have a lot to learn from your last posts, so will spend some
time tomorrow to dig in a bit more.

Regards

5. ## Re: Drawing Arcs

hello,

>Some parts are still mysterious to me, especially the one where you
>explain using a mask instead of a multiplication. well, that may be
>because i'm tired after a pretty long trip today...

ok, here is the trick.
let us say that you KNOW that your first pixel to print is the pixel 2 at
Load X in D1 and load 4 in Ds (because 4 is 0100 or, pixel number 2 set...)

now, the breasenham algo only works by UP/DOWN or LEFT/RIGHT moves...

if you want to move UP, just increate D1 by the length of line (assuming
line lenght is in R0: AD1EX CR0EX.A A+C.A AD1EX CR0EX.A ) and you are done!
you have the address of the pixel one above in D1 and it's mask in Ds. So,
to do a pixon, just do C=DAT1.S C!D.S DAT1=C.S
if you want to move left: DSRB.S ?D#0.S { D1-1 D+8.S } ie: shift the mask 1
bit to the right, if there is still a bit in Ds, all is ok, else it means
that you need to work on pixel 3 (2^3=8) at the previous address...

if you do that, then you only have to calculate the address and mask for 1
pixel (the first one)...

>1) For drawn pixels, i'm using a hand-made multiplication, which is
>faster than standard #MUL call?
>For a standard 131 pixels width screen, it costs 163 cycles, instead
>of 360 as before.
>Quite an improvement, but it is still the most costly operation for a
>drawn pixel.

heuu, if you are working on a standard size screen, you can calculate the
%Aa: Y Ca:X R0:@screen
P=C.0 D0=C C=R0.A % save X in P and D0. C=@Screen
A+A.A C+A.A ASL.A C+A.A % C=C+A*2+A*2*16 -> C=C+A*34: ie: C=@line where
pixel is
AD0EX ASRB.A ASRB.A A+C.A D0=A % D0=@ of the pixel
LC 1248124812481248 P=0 % Load in Cs the mask of the pixel to turn on...
that should be around 120 cycles or so and does all the calculations needed
to turn your pixel on, it only modifies A, C, P and D0...

but anyhow, this is not a problem as, as stated above, you realy only need
to do this once at the begining...

>2) For partial circles (out of area sections), especially for large
>ones,
>the discarding algorithm, although very much improved, still run on a
>per-pixel basis.
>I guess it *could* be faster to discard whole sections if it can be
>easily calculated, at initialisation.
>This is still to be investigated at this stage,
>I have a simple idea in mind currently, based on squares,
>but this is bound to increase code size, so i wonder if this is
>actually worth it.

I think that the discard should be done by quadran... just work on the
quadran where there are pixels that needs turning on... this is the best
because easy to calculate the startup error for a quadran and easy to
calcualte the X/Y coordinates of the pixel at the begining of the quadran...

Just stop bothering about size. Size does mater, in some cases, but not in
this one... there is plenty of space on the calculator so don't sweat it....

regards, cyrille

6. ## Re: Drawing Arcs

On Aug 7, 6:32*am, Yann wrote:
> Hello Jacob
>
> Here is a first try at an ASM Arc Algorithm :http://img21.xooimage.com/files/8/6/...e-arc-v1.0-570...
>
> I've called it Fast Approximative Arc, because it can be wrong by one
> pixel.
> As i was not smart enough to properly understand how you did to check
> if a pixel must be drawn,
> i tried to invent an "homebrew" algorithm, based on circumference
> length
> (The most famous : Circ = 2 x Pi x R).
> Well, on paper, it looks pretty and simple, but it comes with problems
> of its own, especially estimating distance from a trail of pixel and
> correcting cumulated error from the "real" circle.
>
> As a consequence, this version is not directly comparable with yours.
> I would appreciate if you could give me a hand at understanding how
> you test [pixel within arc], this way it would be possible to create a
> code which use the same algorithm, remaining differences only coming
> from programming language.
>
> Well, nonetheless, i'm providing binaries for this version, because it
> can still usefull for comparison in the future.
> Input is as follows : X0, Y0, Radius (in pixel), StartBearing,
> EndBearing (in degree, with 0° being North).
> As approximation error increases with Radius, this version limits R to
> 60 max.
>
> Here are some performance results, from an HP48SX (i expect later
> model to perform better) :
> Full : 0.50s
> Half : 0.29s
> Quarter : 0.18s
> Eight : 0.12s
> 1° * *: 0.07s *(Note : 0° means "Full Circle", so cannot be tested)

Hello Yann,

I finally have some results from running your program on my 50g, here
are the times for the 30 pixel radius circle:
Full: 0.08 seconds
Half: 0.05 seconds
Quarter: 0.04 seconds
Eighth: 0.03 seconds
1 degree: 0.02 seconds

That is incredible!!!! The arc simply appears instantly.

Cyrille, still working on trying to get your arc program running on my
calculator, for some reason no matter what the input when I call xCC I
momentarily see a "ray" or "beam" of approximately 1 octant (octant 1
the screen out to the extent (or close to) of the screen and the stack
is unchanged. This happens even when I provide no input at all. Any
idea as to what I'm doing wrong? I get the same results on Emu48.

Jacob

7. ## Re: Drawing Arcs

> now, the breasenham algo only works by UP/DOWN or LEFT/RIGHT moves...
> if you want to move UP, just increate D1 by the length of line (assuming
> line lenght is in R0: AD1EX CR0EX.A A+C.A AD1EX CR0EX.A ) and you are done!

OK, now i understand why you are not using circle symetry :
you need the previous point and its nibble address to determine the
next one.

That's indeed very clever, good performances, low complexity, quite a
dream.
So be sure that i will make use of it for the next development phase.

I've been using the last few hours at testing a previously mentionned
idea : dynamically generate the code for multiplication during
initialisation, and the results are pretty interesting.
Actually, the funny thing is that now the multiplication code is so
fast (28 cycles for a normal 131 pixels screen) that it costs less
than the jump statements around it (48 cycles).
I couldn't find anything faster (& simpler) than :
A=D0 [16] % this in fact is ==> AD0EX D0=A
APCEX [16]
(... here is the dynamically created code ending with : )
APCEX [16] or PC=A [16]

Well anyway, this was interesting to try, and maybe such a concept
could be reused later.
New performance numbers follows :

FastCircle V2.5 on HP48SX (422 Bytes)
30 pixels (65,32,30) ==> 76ms
60 pixels (30,-10,60) ==> 88ms
200 pixels (60,215,200)==> 184ms

At this level of performance, i was wondering if the header was
becoming a bottleneck,
so i released FastCircle PureCode, for programmers, in order to find
out, and here are the results :

FastCircle PureCode v2.5 on HP48SX (299.5 Bytes)
30 pixels (65,32,30) ==> 56ms
60 pixels (30,-10,60) ==> 66ms
200 pixels (60,215,200)==> 161ms

So it seems that the header does actually cost a fixed 20ms time,
which is not unexpected.

You can find the new binaries for all HP platforms at this address :
http://phantasie.tonempire.net/utili...circle-t58.htm

I believe this is the last release for full circle drawing, as it
seems to be a good enough base to work on the real objective of this

> here is the code in ASM for an arc.
> this is a source from a debug4x project, so it should compile readely if you
> create a project and add this file in (make the project a library)...

Thanks Cyrille. The sources codes you provided do indeed compile fine,
both for Arcs & Circles.
But for some reason, i'm unable to get any "drawn pixel" out of it.
Note that it does not crash either.

I've followed instructions to provide inputs directly in registers as
requested
% input: D0: @ grob %
% Aa: Centre x %
% Ba: Centre y %
% Ca: Rayon %
% R0a: 360-AngleStart*8.93608577019 90°->804%
% R1a: 360-AngleEnd*8.93608577019 %

but to no avail, neither for Arc nor for Circle.

Furthermore, it seems the header you provided with the second code is
intentionnally wiping out input data with values of its own.
Therefore, i was expecting a fixed output from running the code, but
got a blank screen.

It could be this is because i'm testing on HP48 S/G, and the results
might be different on HP49 ?

> I finally have some results from running your program on my 50g

Thanks Jacob for taking the time to test it on your calc. Indeed, this
is encouraging.
I believe i will get rid of the "one pixel approximation" in the next
version, thanks to your explanations on algorithm and thanks to
Cyrille too.

Regards

8. ## Re: Drawing Arcs

hello,

>Thanks Cyrille. The sources codes you provided do indeed compile fine,
>both for Arcs & Circles.
>But for some reason, i'm unable to get any "drawn pixel" out of it.
>Note that it does not crash either.

>I've followed instructions to provide inputs directly in registers as
>requested

% input: D0: @ grob %
% Aa: Centre x %
% Ba: Centre y %
% Ca: Rayon %
% R0a: 360-AngleStart*8.93608577019 90°->804%
% R1a: 360-AngleEnd*8.93608577019 %

>but to no avail, neither for Arc nor for Circle.

does D0 point on the prolog of the GROB object or the data part of the GROB?
if you get it to point on the GROB prolog, it should work....

regards, cyrille

9. ## Re: Drawing Arcs

Hello Cyrille

> does D0 point on the prolog of the GROB object or the data part of the GROB?
> if you get it to point on the GROB prolog, it should work....
>

Yes, it is the prolog, straight from the stack :

C=DAT1.A
D0=C

Regards

10. ## Re: Drawing Arcs

hello,

that is strange.

anyhow, here is an updated version with some optimizations (skip of first
quadran if possible (I thouls do the same for the other quadrant, but I do
not have that much more time to spend on it, so if someone wants to spend
the time....

Right now, using emu 48 for timing, it look like it can draw a 23 pixel
diameter circle in around 8ms....

if you need help in trying to implement the quadran skip for the Q2, Q3, Q4,
just send em an email... what needs to be done is implement the skip code
and remove an extra EXIT in the quatran to skip code at the begiing of the
circle routine...

cyrille

RPL
( C:\Documents and Settings\cydeb\Desktop\circle\circ.S, part of the cr.HPP
project, created by <> on 8/8/2008 )

INCLUDE cr.h

xNAME CC
::
CODEM

SAVE A=DAT1.A A+10.A R4=A.A
A=0.A R2=A.A
{
D0=(5)\$806D5 A=DAT0.A D0=A D1=A D1+20
% erase screen
A=0.W LC 87 { DAT1=A.16 D1+16 C-1.B UPNC }
% angles 1 and 2

D0=(5)\$806D5 A=DAT0.A D0=A
A=0.A R0=A.A LC 00B69 R1=C.A
LA 00045 LC 00020 B=C.A LC 17
GOSUB _Circle P=0

D0=(5)\$806D5 A=DAT0.A D0=A
A=R2.A R0=A.A LC 0010C A+C.A LC 00B69 { A-C.A UPNC } A+C.A R1=A.A
% LA 00Af4 R0=A.A LC 0010C A+C.A LC 00B69 { A-C.A UPNC } A+C.A R1=A.A
LA 00045 LC 00020 B=C.A LC 15
GOSUB _Circle P=0
% LC 01000 { C-1.A UPNC }
A=R2.A A+16.A R2=A.A LC 00B69 ?A>=C.A EXIT UP
}

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %%
% Circle asm toolbox %
% %
% input: D0: @ grob %
% Aa: Centre x %
% Ba: Centre y %
% Ca: Rayon %
% R0a: 360-AngleStart*8.4 %
% R1a: 360-AngleEnd*8.4 %
% the circle must be in the -2047, 2047 square %
% Grob can not be bigger than 2048 pixels %
% %
% Uses: Carry, P, RSTK2 %
% D0 (Last pix Plane1) %
% D1 (Last pix plane2) %
% R3a: +/- Line Width %
% As: Undefine %
% Bs: Undefine %
% All functions are using standard bresenham algo %
% D0 is pointing on the bit plan. %
% During the process, %
% Am: 4*X Error %
% Bm: 4*Y Error %
% Cm: Error %
% Ax: XCurrent %
% Bx: XMax (Grob Width) %
% Cx: YCurrent %
% Dx: YMax (Grob Height) %
% D0: Pointer on bit plan 1 %
% D1: Nb Pixel until we turn pixon ON/OFF %
% ST0: currently not drawing pixel (or drawing) %
% Ds: nuber of pixon/pixof switch before bail out..%
% Bs: bit feilf for quadrant to skip %
% R1a: Nb pixel for next series of Pixon/OFF %
% R3a: Line Width or - Line Width %
% %
% The Bresenham algo is use to draw the circle. %
% The original Bresenham use to compute the circle %
% Only on 1/8 of the circle and draw the other part%
% using symetrie. Doing a full pixon is quite slow %
% with a saturn, so, we are using 8 times %
% bresenham to draw suxcecivly the 8 octants of %
% the circle. Am, Bm and Cm are use to store the %
% values needed by bresenam, Ax, Bx, Cx and Dx are %
% used to store the current pixel coordinates %
% and the grob dimention to perform the cliping. %
% D0 and Cs are use to point on the current %
% pixel. %
% %
% The algo we are using is: %
% X=2*Rayon-1 %
% Y=1 %
% cx=cx+rayon %
% cy=cy %
% Error = 0 %
% pixon(Cx, Cy) %
% while Y % Begin %
% Error=Error+Y %
% Y=Y+2 %
% cy=cy+1 %
% If error>=X then %
% Begin %
% error= error-X %
% X=X-2 %
% cx=cx-1 %
% End %
% pixon(Cx, Cy) %
% End; %
% while X<>0 do %
% Begin %
% Error=Error-X %
% X=X-2 %
% cx=cx-1 %
% If error<0 then %
% Begin %
% error= error+Y %
% Y=Y+2 %
% cy=cy+1 %
% End %
% pixon(Cx, Cy) %
% End; %
% %
% The same routine is used all the time, but %
% a different Pixon routine is copied in IRAMBUFF %
% for each type of line, and this routine is used %
% to affect the pixels. the _Prepx routine are used%
% to copy the pixon routine in RAM. Note that to %
% decrease teh amount of used register by this %
% routine, the code is charged in Cm using LC with %
% P=3. in order to have a readable code, the LC %
% mnemonic is not used, bu is replaced by the hex %
% opcode: 3x where x is the number of nibbles to %
% load in C-1. at the end of the routine, C[34] are%
% loaded with 00. This means the this part of the %
% Ca register is lost %
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %%
*_Circle
?C=0.A RTY % Fast exit if radius = 0

ST=0.1 ST=0.2 ST=0.0 % by default, start with pixel not drawn... the ST1 and
2 are here for protection so the add do not change other flags
D=0.S D+1.S
B=0.S
AR1EX.A CR0EX.A ?C angle, Aa: radius, R0: A2-A1, R1: Cx
% D= C*A/512 -> D= Angle*8.9*R/512 -> A*2*pi*R/360 -> number of pixels from
0° to Angle
ST=0.3
?C#0.A
{
D-1.S CSTEX C+1.A CSTEX
ST=1.3
} SKELSE {
% build a bitfeild for every quadran that needs to be skipped before we
start painting
?ST=0.0 { { D=C.A LC 002D5 D-C.A EXITC B+1.S D-C.A EXIT EXITC B+2.S D-C.A
EXITC B+4.S D-C.A EXITC B+8.S } C+D.A }
D=0.A
?ABIT=0.0 { D+C.A } C+C.A
?ABIT=0.1 { D+C.A } C+C.A
?ABIT=0.2 { D+C.A } C+C.A
?ABIT=0.3 { D+C.A } C+C.A
?ABIT=0.4 { D+C.A } C+C.A
?ABIT=0.5 { D+C.A } C+C.A
?ABIT=0.6 { D+C.A } C+C.A
?ABIT=0.7 { D+C.A } DSRB.A
?ABIT=0.8 { D+C.A } DSRB.A
?ABIT=0.9 { D+C.A } DSRB.A
?ABIT=0.10 { D+C.A } DSRB.A
?ABIT=0.11 { D+C.A } DSRB.A
DSR.A
C=D.A D1=C % D1: number of pixel to first change Ca: A2-A1
}
C=R0.A D=0.A
?ABIT=0.0 { D+C.A } C+C.A
?ABIT=0.1 { D+C.A } C+C.A
?ABIT=0.2 { D+C.A } C+C.A
?ABIT=0.3 { D+C.A } C+C.A
?ABIT=0.4 { D+C.A } C+C.A
?ABIT=0.5 { D+C.A } C+C.A
?ABIT=0.6 { D+C.A } C+C.A
?ABIT=0.7 { D+C.A } DSRB.A
?ABIT=0.8 { D+C.A } DSRB.A
?ABIT=0.9 { D+C.A } DSRB.A
?ABIT=0.10 { D+C.A } DSRB.A
?ABIT=0.11 { D+C.A } DSRB.A
DSR.A
C=D.A ?ST=0.3 { D1=C } ACEX.A AR1EX.A % R1: number of pixel from A1 to A2,

A+C.A % Compute cx (cx+Rayon)
C=0.M C+C.A CSL.A CSL.A CSL.W % Cm=Rayon*2

D0+10 C=DAT0.X C=D.S D=C.W % Dx: MaxY Dm: Rayon*2 Ds: nb pixel
color changes...
D0+5 C=DAT0.A RSTK=C C+7.A CSRB.A CSRB.A CBIT=0.0 R3=C.A % Compute line
width
D0+5

% Aa: cx, Ba: cy, Ca: line lenght, D0: @screen D0=D0+B*C+A/4. Do not modify
Aa and Ba

% We must now compute the position of the first pixel
AD0EX ABEX.A % D0: cx Ba: @Screen, Aa: cy Ca: line width
C+C.A
?ABIT=0.1 { B+C.A } C+C.A % We Want: D0=@Pix+Y*Width+X/4,
?ABIT=0.2 { B+C.A } C+C.A % Step 1: Compute B=B+Y*Width ( Width even <=
512 )
?ABIT=0.3 { B+C.A } C+C.A
?ABIT=0.4 { B+C.A } C+C.A
?ABIT=0.5 { B+C.A } C+C.A
?ABIT=0.6 { B+C.A } C+C.A
?ABIT=0.7 { B+C.A } C+C.A
?ABIT=0.8 { B+C.A } C+C.A
?ABIT=0.9 { B+C.A }
% D0: cx Ba: @Pixel, Aa: cy
CD0EX D0=C % Ca=X
P=C.0 CSRB.A CSRB.A B+C.A % Compute pixel address
ABEX.A AD0EX % Restore Ba=Ba, Aa=Aa, D0 point on pixel on plan
1
LC 1248124812481248 P=0 % Compute pixel mask

C=RSTK BCEX.A % Bx: max X Cx: current y

{ ?ST=0.0 EXIT ?A>=B.X EXIT ?C>=D.X EXIT A=DAT0.S A!C.S DAT0=A.S } % Pixon
( With cliping )

% First quadrant. do we need to bypass this quadrant or not?
SB=0 BSRB.S ?SB=0 { } SKNC { GOTO .Do_Bypass_Q1 }
% test for bypass of this quadran..
DSRC DSRC DSRC DSRB.A CDEX.A % Ca: radius
D+C.X A-C.X % Update current X and Y
% Also need to move the pixel pointer... and this without modifying ANY
registers!
AD0EX ABEX.A AR3EX.A % Ba: @ pixel, Aa: line width, Ca: radius
B=B+A*C. note, A<512 and even
C+C.A
?ABIT=0.1 { B+C.A } C+C.A P=C.0
CSR.A B-C.A CSL.A C=P.0 % remove radius /4
?ABIT=0.2 { B+C.A } C+C.A
?ABIT=0.3 { B+C.A } C+C.A
?ABIT=0.4 { B+C.A } C+C.A
?ABIT=0.5 { B+C.A } C+C.A
?ABIT=0.6 { B+C.A } C+C.A
?ABIT=0.7 { B+C.A } C+C.A
?ABIT=0.8 { B+C.A }
C=P.0 { C-4.B EXITC CSRB.S ?C#0.S UP B-1.A C+8.S UPNC }
CSR.A CSR.A % restore C (radius)
AR3EX.A ABEX.A AD0EX % restore updated D0, Aa and Ba
CDEX.A D+D.A DSLC DSLC DSLC P=14 % restore Current Y, max Y and radius
SKIP {
*.Do_Bypass_Q1
C=D.M A=C.M % X=Am=Rayon
C=0.M % Y=Cm=0
B=0.M % Er=0
A-1.M C+1.M % Because the bresenham algo need to add -(X-1) or
P=14
% Octant 1 From a=0 to - 45
{
?A<=C.M EXIT % End of octant? X B+C.M % er+Y
C+2.M C+1.X % Y+2, cy+1
CR3EX.W % cy+1 part2
CR3EX.W

D1-1 SKNC { CD1EX CR1EX.A CD1EX D-1.S RTNC CSTEX C+1.A CSTEX } % count
pixels, turn pixelON Flag on/off as needed, update counter

?B= X
{
B-A.M % er - X
A-2.M A-1.X % X-2, cx-1
CSRB.S ?C#0.S { C+8.S D0-1 } % cx-1 part2
} % Else, error<0
?ST=0.0 UP ?A>=B.X UP ?C>=D.X UP A=DAT0.S A!C.S DAT0=A.S UPNC % Pixon (
With cliping )
}
% Octant 2. From a=-45 to -90
{
?A#0.P EXIT % End of octan?
B-A.M % er - X
A-2.M A-1.X % X-2, cx-1
CSRB.S ?C#0.S { C+8.S D0-1 } % cx-1 part2

D1-1 SKNC { CD1EX CR1EX.A CD1EX D-1.S RTNC CSTEX C+1.A CSTEX } % count
pixels, turn pixelON Flag on/off as needed, update counter

?B=0.P % if B>0 then do nothing
{ % else,
B+C.M C+2.M C+1.X % er+Y, Y+2, cy+1
CR3EX.W % cy+1 part2
CR3EX.W
}
?ST=0.0 UP ?A>=B.X UP ?C>=D.X UP A=DAT0.S A!C.S DAT0=A.S UPNC % Pixon (
With cliping )
}
}
% Octant 3 From a=-90 to -135
% Doing the same thing again, but inverting Y and X
C=D.M A=C.M B=0.M C=0.M % ReInitializing values
A-1.M C+1.M % Because the bresenham algo need to add -(X-1) or
{
?A<=C.M EXIT % End of octant? X B+C.M % er+Y
C+2.M A-1.X % Y+2, cx-1
CSRB.S ?C#0.S { C+8.S D0-1 } % cx-1 part2

D1-1 SKNC { CD1EX CR1EX.A CD1EX D-1.S RTNC CSTEX C+1.A CSTEX } % count
pixels, turn pixelON Flag on/off as needed, update counter

?B= X
{
B-A.M % er - X
A-2.M C-1.X % X-2, cy-1
CR3EX.W % cy-1 part2
CR3EX.W
} % Else, error<0
?ST=0.0 UP ?A>=B.X UP ?C>=D.X UP A=DAT0.S A!C.S DAT0=A.S UPNC % Pixon (
With cliping )
}
% Octant 4. From a=-135 to -180
{
?A#0.P EXIT % End of octan?
B-A.M % er - X
A-2.M C-1.X % X-2, cy-1
CR3EX.W % cy-1 part2
CR3EX.W

D1-1 SKNC { CD1EX CR1EX.A CD1EX D-1.S RTNC CSTEX C+1.A CSTEX } % count
pixels, turn pixelON Flag on/off as needed, update counter

?B=0.P % if B>0 then do nothing
{ % else,
B+C.M C+2.M A-1.X % er+Y, Y+2, cx-1
CSRB.S ?C#0.S { C+8.S D0-1 } % cx-1 part2
}
?ST=0.0 UP ?A>=B.X UP ?C>=D.X UP A=DAT0.S A!C.S DAT0=A.S UPNC % Pixon (
With cliping )
}
% Octant 5 From a=-180 to -225
% Doing the same thing again, but inverting Y and X again and differantly
C=D.M A=C.M B=0.M C=0.M % Reinitializing values
A-1.M C+1.M % Because the bresenham algo need to add -(X-1) or
{
?A<=C.M EXIT % End of octant? X B+C.M % er+Y
C+2.M C-1.X % Y+2, cy-1
CR3EX.A % cy-1 part2
CR3EX.A

D1-1 SKNC { CD1EX CR1EX.A CD1EX D-1.S RTNC CSTEX C+1.A CSTEX } % count
pixels, turn pixelON Flag on/off as needed, update counter

?B= X
{
B-A.M % er - X
A-2.M A+1.X % X-2, cx+1
C+C.S SKNC { C+1.S D0+1 } % cx+1 part2
} % Else, error<0
?ST=0.0 UP ?A>=B.X UP ?C>=D.X UP A=DAT0.S A!C.S DAT0=A.S UPNC % Pixon (
With cliping )
}
% Octant 6. From a=-225 to -270
{
?A#0.P EXIT % End of octan?
B-A.M % er - X
A-2.M A+1.X % X-2, cx+1
C+C.S SKNC { C+1.S D0+1 } % cx+1 part2

D1-1 SKNC { CD1EX CR1EX.A CD1EX D-1.S RTNC CSTEX C+1.A CSTEX } % count
pixels, turn pixelON Flag on/off as needed, update counter

?B=0.P % if B>0 then do nothing
{ % else,
B+C.M C+2.M C-1.X % er+Y, Y+2, cy-1
CR3EX.A % cy-1 part2
CR3EX.A
}
?ST=0.0 UP ?A>=B.X UP ?C>=D.X UP A=DAT0.S A!C.S DAT0=A.S UPNC % Pixon (
With cliping )
}
% Octant 7 From a=-270 to -315
% Doing the same thing again, but inverting Y and X again and differantly
C=D.M A=C.M B=0.M C=0.M % Reinitializing values
A-1.M C+1.M % Because the bresenham algo need to add -(X-1) or
{
?A<=C.M EXIT % End of octant? X B+C.M % er+Y
C+2.M A+1.X % Y+2, cx+1
C+C.S SKNC { C+1.S D0+1 } % cx+1 part2

D1-1 SKNC { CD1EX CR1EX.A CD1EX D-1.S RTNC CSTEX C+1.A CSTEX } % count
pixels, turn pixelON Flag on/off as needed, update counter

?B= X
{
B-A.M % er - X
A-2.M C+1.X % X-2, cy+1
CR3EX.A % cy+1 part2
CR3EX.A
} % Else, error<0
?ST=0.0 UP ?A>=B.X UP ?C>=D.X UP A=DAT0.S A!C.S DAT0=A.S UPNC % Pixon (
With cliping )
}
% Octant 8. From a=-315 to -360
{
B-A.M % er - X
A-2.M C+1.X % X-2, cy+1
CR3EX.A % cy+1 part2
CR3EX.A

D1-1 SKNC { CD1EX CR1EX.A CD1EX D-1.S RTNC CSTEX C+1.A CSTEX } % count
pixels, turn pixelON Flag on/off as needed, update counter

?B=0.P % if B>0 then do nothing
{ % else,
B+C.M C+2.M A+1.X % er+Y, Y+2, cx+1
C+C.S SKNC { C+1.S D0+1 } % cx+1 part2
}
?A#0.P EXIT % End of octan?
?ST=0.0 UP ?A>=B.X UP ?C>=D.X UP A=DAT0.S A!C.S DAT0=A.S UPNC % Pixon (
With cliping )
}
P=0 RTN

ENDCODE

;

"Yann" wrote in message
> Hello Cyrille
>
>> does D0 point on the prolog of the GROB object or the data part of the
>> GROB?
>> if you get it to point on the GROB prolog, it should work....
>>

>
> Yes, it is the prolog, straight from the stack :
>
> C=DAT1.A
> D0=C
>
>
> Regards
>

11. ## Re: Drawing Arcs

Thanks Cyrille, i will look into it

12. ## Re: Drawing Arcs

OK, Fine, i've got it working on a HP48GX.

It seems to produce an "animation" with a small arc traveling into a
larger full-circle.
I expect this is fully intended by the header you produced.

HP48SX on the other hand does not display anything (but there is some
activity for sure)
I noticed that you selected a fixed address for output, \$806D5, which
seems to be =ADISP (->Stack grob).
Maybe GX and SX do not have the same behavior with it.
For example, this could be because the screen is not "refreshed" while
the ASM code is running.

OK, so for now i cannot time your code, but i guess i just need to
rewrite the header and that should be ok.
With such a speed announced, i believe there is plenty to learn from

Regards

13. ## Re: Drawing Arcs

hello,

> HP48SX on the other hand does not display anything (but there is some
> activity for sure)
> I noticed that you selected a fixed address for output, \$806D5, which
> seems to be =ADISP (->Stack grob).
> Maybe GX and SX do not have the same behavior with it.
> For example, this could be because the screen is not "refreshed" while
> the ASM code is running.

On the SX, the address of the display is not the same than the GX.. so, on
the SX, you need to change \$806D5 to some other address to get the demo
working...

if all you want to do is create an ARC program that takes a gROB as input,
it will be compatible for SX/GX...
if running on an apple, you can probably replace some of the code
(multiplications) by some optimized multiplications instructions...

> With such a speed announced, i believe there is plenty to learn from

:-) well, I do have some experience developing Saturn code... so that
helps...

regards, cyrille

14. ## Re: Drawing Arcs

On Mon, 11 Aug 2008 17:52:25 -0500, Yann wrote:

> OK, Fine, i've got it working on a HP48GX.
> HP48SX on the other hand does not display anything...
> a fixed address for output, \$806D5, which seems to be =ADISP (->Stack grob).
> Maybe GX and SX do not have the same behavior with it.

Mika's "ent-srt.doc" (an old bible says:

70000 - 707D9 RAM pointer & status area [S/SX]

Pointer Name Description
7055B VDISP Current display grob
70560* PDISP Pict grob???
70565 GDISP Graphic display grob
7056A* TEMPBOT Bottom of tempob area (?)
7056F TEMPTOP Top of tempob area
70574* RETTOP Top of rpl return stack
FREE RAM
70579 DSKTOP Top of stack
7057E* DSKBOT Bottom of stack[*] not "supported"

Whereas in G/GX: [non-rom starts at 80000 rather than 70000]

806DA VDISP
806DF PDISP
806E4 GDISP
806E9 TEMPBOT
806EE TEMPTOP
806F3 RETTOP
806F8 DSKTOP
806FD DSKBOT

To get the same document:

http://www.hpcalc.org/search.php?query=ent_srt

[r->] [OFF]

15. ## Re: Drawing Arcs

Hello

I rewrote the header of your code, Cyrille, in order to have it using
the same convention as Jacob (Bearing 0° is North, Clockwise) and
output in Graphical display, for both HP48SX & GX.

http://phantasie.tonempire.net/utili...arc-t59.htm#61

No problem with speed, it is hand down the fastest code around, with
output in the less-than-40ms zone for 48GX, including SysRPL header

However, there are still some issues with this version :

1) Accuracy is not correct. I've displayed some screenshots in the
I think this is a direct consequence of the selected methodology
(pixel counting).
I had the same issue with my first code some time ago, with equivalent
accuracy consequences.

2) The first quarter is sometimes not drawn. Probably a bug into the
I tried to remove it in order to release a usable binary, but
unfortunately it produced additionnal side effects, such as a sudden
90° output shift depending on input values (try Start Bearing = -1° &
+1°).

The bug can probably be corrected, but the accuracy may require a
different methodology, potentially resulting non-trivial code changes.

As a personal sidenote, i must add that your code provided me with the
perfect opportunity to start learning MASD. So thanks for your
contribution.

16. ## Re: Drawing Arcs

just to read this posting gives me
as a log time hp user (1st my very own was HP-21)
a very warm feeling

thank you Cyrille and U 2, Yann
VPN

"Yann" wrote in message
Hello

I rewrote the header of your code, Cyrille, in order to have it using
the same convention as Jacob (Bearing 0° is North, Clockwise) and
output in Graphical display, for both HP48SX & GX.

http://phantasie.tonempire.net/utili...arc-t59.htm#61

No problem with speed, it is hand down the fastest code around, with
output in the less-than-40ms zone for 48GX, including SysRPL header

However, there are still some issues with this version :

1) Accuracy is not correct. I've displayed some screenshots in the
I think this is a direct consequence of the selected methodology
(pixel counting).
I had the same issue with my first code some time ago, with equivalent
accuracy consequences.

2) The first quarter is sometimes not drawn. Probably a bug into the
I tried to remove it in order to release a usable binary, but
unfortunately it produced additionnal side effects, such as a sudden
90° output shift depending on input values (try Start Bearing = -1° &
+1°).

The bug can probably be corrected, but the accuracy may require a
different methodology, potentially resulting non-trivial code changes.

As a personal sidenote, i must add that your code provided me with the
perfect opportunity to start learning MASD. So thanks for your
contribution.

17. ## Re: Drawing Arcs

On Aug 12, 5:27*pm, "Veli-Pekka Nousiainen"
wrote:
> just to read this posting gives me
> as a log time hp user (1st my very own was HP-21)
> a very warm feeling
>
> thank you Cyrille and U 2, Yann
> VPN

You are a *logarithmic* time HP calulator user?
Hmm.........

18. ## Re: Drawing Arcs

at least if you look back
then timescale seems to be compressed
:-D
On Aug 12, 5:27 pm, "Veli-Pekka Nousiainen"
wrote:
> just to read this posting gives me
> as a log time hp user (1st my very own was HP-21)
> a very warm feeling
>
> thank you Cyrille and U 2, Yann
> VPN

You are a *logarithmic* time HP calulator user?
Hmm.........

19. ## Re: Drawing Arcs

At last,
here is a (long awaited) usable version for Fast Arc, which seems
reasonably accurate to be of any use.

The binaries for HP48, 49 and 50 can be downloaded at this website :
http://fastarc.webhop.org/

Input :
6 : Grob (<-- Optional, if none provided, will draw into Graphic Area)
5 : X0
4 : Y0
2 : Start Bearing (°)
1 : End Bearing (°)

Being based on the code sample by Cyrille de Brebisson, it is quite
fast, although after completing the fullcircle code, the focus was no
longer speed, but rather arc accuracy, and getting something out of
the door before any real life issues prevent me from working on it.
Version 1 seems now completed. This version have the following change
compared to previous releases :

1) Accurary :
Granted, the algorithm is still at its core based on an approximation,
but this time, approximation should be less than one pixel, meaning in
fact full accuracy as far as display is concerned.
I've tried to trick the program in a number of way, and could no
longer find any blatant loophole with this version.
Some samples screenshots are provided in the link for illustration

2) Breisenham's cache
Well, i wanted to bring something new, so here it is.
I added a simple but effective cache algorithm, which allows to run
breisenham only once, reusing output for all octants. It significantly
improves performances and makes the code shorter (a simple read-cache
replace the optimized breisenham algo within each octant).

3) Expanded Boundaries
Due to improvements in register allocation, the input limits are now
fairly large, up to 250 000.
It is also possible to define X0 and Y0 (the center of the circle) as
negative values.

Thanks to Cyrille's "nibble traveler" methodology, which avoids
calculating memory pixel location, performance are good.
As a funny side effect, now the program spends more time in the header
than drawing the arc. This was tested with the "PureCode" version,
which removes the header, and it resulted in 31ms being spent on
header alone (on GX), which means twice more time than is necessary to
draw a 30pixels half-circle on the same platform.
Of course, performances on newer platform should be even better.

There are still some room for improvement though, especially as i
really did not optimized the "arc specific" part of the code. This is
partly because my focus was much more on getting something accurate
and fastly available.

Some ideas which could make it in a future release if need be :
- Sector discarding : this avoids to "loop" for each not-drawed pixel,
improving performances for circles with parts out of screen. Of
course, this cost some bytes to program.
- Dynamic compilation : the program would create the code which draws
Arc, using inputs to optimized tests and loops. This will improve
performance by a good margin, and potentially reduce code size too. It
is complex though, and make maintenance more difficult. So this is
rather a "last move" to do, when everything else is stable.

Well, i guess the next move could be on functionality, instead of ever
more performances.
For example, how to allow a user to "replace" the embedded "Arc"
function with this one ?
Would a "forced save" with "ARC" global name in the HOME directory be
enough for this ?
Eventually, i can also add some more features to the header to make it
compatible to HP syntax on top of the one already documented in this
thread. Well, if that is usefull...

20. ## Re: Drawing Arcs

On Aug 14, 7:08*pm, Yann wrote:
> At last,
> here is a (long awaited) usable version for Fast Arc, which seems
> reasonably accurate to be of any use.
>
> The binaries for HP48, 49 and 50 can be downloaded at this website :http://fastarc.webhop.org/
>
> Input :
> 6 : Grob (<-- Optional, if none provided, will draw into Graphic Area)
> 5 : X0
> 4 : Y0
> 2 : Start Bearing (°)
> 1 : End Bearing (°)
>
> Being based on the code sample by Cyrille de Brebisson, it is quite
> fast, although after completing the fullcircle code, the focus was no
> longer speed, but rather arc accuracy, and getting something out of
> the door before any real life issues prevent me from working on it.
> Version 1 seems now completed. This version have the following change
> compared to previous releases :
>
> 1) Accurary :
> Granted, the algorithm is still at its core based on an approximation,
> but this time, approximation should be less than one pixel, meaning in
> fact full accuracy as far as display is concerned.
> I've tried to trick the program in a number of way, and could no
> longer find any blatant loophole with this version.
> Some samples screenshots are provided in the link for illustration
>
> 2) Breisenham's cache
> Well, i wanted to bring something new, so here it is.
> I added a simple but effective cache algorithm, which allows to run
> breisenham only once, reusing output for all octants. It significantly
> improves performances and makes the code shorter (a simple read-cache
> replace the optimized breisenham algo within each octant).
>
> 3) Expanded Boundaries
> Due to improvements in register allocation, the input limits are now
> fairly large, up to 250 000.
> It is also possible to define X0 and Y0 (the center of the circle) as
> negative values.
>
> Thanks to Cyrille's "nibble traveler" methodology, which avoids
> calculating memory pixel location, performance are good.
> As a funny side effect, now the program spends more time in the header
> than drawing the arc. This was tested with the "PureCode" version,
> which removes the header, and it resulted in 31ms being spent on
> header alone (on GX), which means twice more time than is necessary to
> draw a 30pixels half-circle on the same platform.
> Of course, performances on newer platform should be even better.
>
> There are still some room for improvement though, especially as i
> really did not optimized the "arc specific" part of the code. This is
> partly because my focus was much more on getting something accurate
> and fastly available.
>
> Some ideas which could make it in a future release if need be :
> - Sector discarding : this avoids to "loop" for each not-drawed pixel,
> improving performances for circles with parts out of screen. Of
> course, this cost some bytes to program.
> - Dynamic compilation : the program would create the code which draws
> Arc, using inputs to optimized tests and loops. This will improve
> performance by a good margin, and potentially reduce code size too. It
> is complex though, and make maintenance more difficult. So this is
> rather a "last move" to do, when everything else is stable.
>
> Well, i guess the next move could be on functionality, instead of ever
> more performances.
> For example, how to allow a user to "replace" the embedded "Arc"
> function with this one ?
> Would a "forced save" with "ARC" global name in the HOME directory be
> enough for this ?
> Eventually, i can also add some more features to the header to make it
> compatible to HP syntax on top of the one already documented in this
> thread. Well, if that is usefull...

Hello Yann,

This is terrific!!! I've done some tests and everything looks great.
Here are my results using a 50g with the same input values you were
using for your 48 tests (Fastarc_v1.hp49&50.hp):

30px, Quarter Circle: 25ms
30px, Half Circle: 26ms
30px, Full Circle: 30ms
60px, Full Circle: 33ms
150px, 3/4 Circle: 41ms

Much faster than my SysRPL program :-), congratulations on your
incredible success.

Jacob