FILLCIRCLE_P()
02-22-2020, 10:57 PM
Post: #1
 DrDarius Junior Member Posts: 41 Joined: Oct 2019
FILLCIRCLE_P()
HP Prime does not have a function which draws a filled circle. I have seen many attempts to implement a substitute by drawing concentric circles with one pixel increment radii, but it does not work well, and the area of such a circle is usually not uniform.

Recently I was working on an application that really could use such a filled circle... it was not absolutely necessary, but it definitely look nice... I decided to spend an hour or two on writing such a procedure.
Maybe somebody will find it useful, and will save time he would otherwise have to spend on writing it.

A program below consists of a procedure drawing a filled circle (FILLCIRCLE_P), and a few small demo/test additions. FILLCIRCLE_P() can be included in the program, or in a library. It draws a filled polygon (a function supported by HP Prime) which vertices are placed on the perimeter of the circle. (One of many methods to draw a filled circle; I am not saying the best one or the fastest one.)

Code:
EXPORT FILLCIRCLE_P (nG, nX, nY, nRadius, nSmoothness, nColor) BEGIN   // Print filled circle ver. 1.2, (c) dap, 2020   // Arguments:   // nG - graphic variable to use for printing   // nX, nY - pixel coordinates of the center of the circle   // nRadius - radius of the circle (in pixels)   // nSmoothness - smoothness of the circle defined as length of sagitta (in pixels, may be fractional)   // nColor - color of the circle   // Returns 0 if no error, (-1) if nSmoothness below limit   LOCAL lVertices = {};   LOCAL I, nHAngleBuffer, nAlpha, nNumberOfPoints;   // check input parameters   IF nSmoothness<0.05 THEN     RETURN (-1);   END;   nHAngleBuffer := HAngle;   HAngle := 1;    // set angle to degrees   // caclulate angle increment   nNumberOfPoints := CEILING(90/(2*ACOS(1-nSmoothness/nRadius)));   nAlpha := 90/nNumberOfPoints;        // calculate polygon vertices   nNumberOfPoints := FLOOR (nNumberOfPoints);   FOR I FROM 1 TO nNumberOfPoints DO     lVertices(I) := (nX+ROUND(nRadius*SIN((I-1)*nAlpha),0), nY-ROUND(nRadius*COS((I-1)*nAlpha),0));     lVertices(nNumberOfPoints+I):= (nX+(nY-IM(lVertices(I))), nY+(RE(lVertices(I))-nX));     lVertices(2*nNumberOfPoints+I):= (2*nX-(RE(lVertices(I))), 2*nY-(IM(lVertices(I))));     lVertices(3*nNumberOfPoints+I):= (nX+(IM(lVertices(I))-nY), nY-(RE(lVertices(I))-nX));   END;   // print polygon   FILLPOLY_P (nG, lVertices, nColor);   // *** for debugging ***   // print vertices   // when enabled, vertices are marked with white dots   // (to see vertices only, comment out  FILLPOLY_P above)   // FOR I FROM 1 TO SIZE(lVertices) DO   //   PIXON_P (G0, RE(lVertices(I)), IM(lVertices(I)), RGB(255,255,255));   // END;      HAngle := nHAngleBuffer;  // restore previous angle setting   RETURN 0; END; // *** DEBUGGING/TEST PROCEDURES *** //      (exit by pressing Esc) // prototypes  WAIT_FOR_ESCAPE_KEY (); EXPORT SPEED_TEST () BEGIN   // test speed    // prints concentric circles of given smoothness and calculates printing times   LOCAL I, J, nIndex, R, G, B;   LOCAL nTStart, nTAccumulated;   LOCAL nRuns := 100;   LOCAL nSmoothness;   LOCAL lSmoothness :=  {0.1, 0.2, 0.5, 1.0, 2.0, 5.0};   CHOOSE(nIndex, "Choose smoothness", "0.05", "0.1", "0.2", "0.5", "1.0", "2.0","0.05 one time","2.0 one time");   CASE     IF (nIndex==7) THEN       nSmoothness := 0.05;       nRuns := 1;     END;      IF (nIndex==8) THEN       nSmoothness := 2.0;       nRuns := 1;     END;     DEFAULT       nSmoothness := lSmoothness(nIndex);     END;  // CASE      STARTVIEW(-1);   RECT(RGB(0,0,0));   FOR I FROM 16 DOWNTO 1 DO     nTAccumulated := 0;     FOR J FROM 0 TO nRuns DO       R := RANDINT(0,255);       G := RANDINT(0,255);       B := RANDINT(0,255);        nTStart := TICKS();       FILLCIRCLE_P (G0, 160, 120, I*10, nSmoothness, RGB(R, G, B));       nTAccumulated := nTAccumulated+(TICKS()-nTStart);     END;     TEXTOUT_P (nTAccumulated/nRuns, 2, 10+12*(I-1), 1, RGB(255,255,0));   END;    WAIT_FOR_ESCAPE_KEY (); END; EXPORT SMOOTHNESS_TEST () BEGIN   // prints 12 circles of different smoothness   LOCAL I, J;   LOCAL lSmoothness := {0.05, 0.1, 0.2, 0.5, 0.8, 1.0, 1.5, 2.0, 4.0, 6.0, 8.0, 9.0};   STARTVIEW(-1);   RECT(RGB(0,0,0));   FOR J FROM 1 TO 3 DO     FOR I FROM 1 TO 4 DO       FILLCIRCLE_P (G0, 64*I, 60*J, 24, lSmoothness(I+(J-1)*4), RGB(255,0,0));       TEXTOUT_P (STRING(lSmoothness(I+(J-1)*4),2,2),  64*I-10, 60*J-4, 2, RGB(255,255,255));     END;   END;    WAIT_FOR_ESCAPE_KEY (); END; EXPORT JUST_ONE_CENTERED_CIRCLE () BEGIN   // prints single centered circle   STARTVIEW(-1);   RECT(RGB(0,0,0));   FILLCIRCLE_P (G0, 160, 120, 100, 0.05, RGB(255,0,0));   LINE_P(G0, 0, 120, 319, 120, RGB(0,255,0));   LINE_P(G0, 160, 0, 160, 239, RGB(0,255,0));   WAIT_FOR_ESCAPE_KEY (); END;  EXPORT BUBBLES () BEGIN   // prints circles of random color, size, and smoothness at random locations   STARTVIEW(-1);   RECT(RGB(255,255,255));   REPEAT     FILLCIRCLE_P (G0, RANDINT(0,319), RANDINT(0,239), RANDINT(5,80), RANDINT(5,500)/100, RGB(RANDINT(0,255),RANDINT(0,255),RANDINT(0,255)));     WAIT(0.5);   UNTIL GETKEY()==4; END; // *** supporting procedures *** WAIT_FOR_ESCAPE_KEY () BEGIN   // wait until Esc key is pressed   LOCAL nKey;   REPEAT     nKey:=GETKEY;   UNTIL nKey==4; END;
The code is very simple and self explanatory.

One comment I would like to make is that the first, initial version of the code was not taking advantage of the symmetry of circle quadrants. I optimized the code later counting on increase of the speed of drawing. To my surprise, the increase of speed was smaller than 20%! This means that either calculation of trigonometric functions is fast, or that calculations related to list indexing and/or drawing filled polygon is slow. I did not have time to explore this subject deeper.

Darius
02-22-2020, 11:22 PM
Post: #2
 Carlos295pz Senior Member Posts: 365 Joined: Sep 2015
RE: FILLCIRCLE_P()
Some firmwares ago that feature was added.
Syntax:
ARC(G, x, y, r or {rx, ry}, [∠1, ∠2], [border_color, [fill_color]])
Also: Program catalog/New/Example/Demo_ARC

Viga C | TD | FB
02-23-2020, 01:10 AM
Post: #3
 DrDarius Junior Member Posts: 41 Joined: Oct 2019
RE: FILLCIRCLE_P()
(02-22-2020 11:22 PM)Carlos295pz Wrote:  Some firmwares ago that feature was added.

Well, yeah.

You are absolutely correct, Carlos. The description of this feature can be found in the Prime help. But if you look at the user's manual, it says:
ARC_P(G, x, y, r [ , a1, a2, c])

Lesson to learn: every time you use a function, look it up in the calculator's help. (I am being facetious. I don't have time to go through every help item in the calculator every time the f/w update is released. On the other hand, I would not mind getting an updated user's manual with it. Or, at least, errata/what's new file.)

A serious conclusion is that the user's manual is outdated and, as such, cannot be trusted.

Okay, let's end this rant here, and look for the bright side: at least I had some fun with solving a trivial math problem.

Darius
03-01-2020, 01:25 AM
Post: #4
 tgallo Junior Member Posts: 47 Joined: Dec 2013
RE: FILLCIRCLE_P()
Thanks for pointing this out Carlos. I had no idea they expanded ARC to fill in circles. I just modified all my games that I wrote that used the old method (drawing concentric circles with one pixel increment radii)
 « Next Oldest | Next Newest »

User(s) browsing this thread: 1 Guest(s)