Author Topic: Seeking best ellipse fill function. (For everyone's sake.)  (Read 22643 times)

0 Members and 1 Guest are viewing this topic.

Offline Pete

  • Forum Resident
  • Posts: 2361
  • Cuz I sez so, varmint!
Re: Seeking best ellipse fill function. (For everyone's sake.)
« Reply #120 on: February 13, 2019, 04:29:36 pm »
Oh guys, BTW - This dots "issue" affects both the SQR and non SQR looping method. I think you both realize that, but just in case.

Pete
Want to learn how to write code on cave walls? https://www.tapatalk.com/groups/qbasic/qbasic-f1/

Offline STxAxTIC

  • Library Staff
  • Forum Resident
  • Posts: 1091
  • he lives
Re: Seeking best ellipse fill function. (For everyone's sake.)
« Reply #121 on: February 13, 2019, 06:20:34 pm »
Whoa man, so much to catch up on.

  • I like the idea of having a CircleFill function being a special case of an EllipseFill function curried down to have a=b=r. Let's keep that idea fo sho.

  • Since the tilted ellipse is a different beast than the flat one, I think a two-function dichotomy is the way to go on that issue. If one breaks in the future for some ungodly reason, someone won't be tempted to toss out both. Plus all that trig might intimidate some folks.

  • As for the questions about individual pixels, dots on each end, and so on - there's a relatively simple way to settle this using the area equation. Namely, the area of an ellipse is precisely pi*a*b. So this means: Count the number of pixels put on screen for any given fill method, whether it be with or without those extra dots. Whichever one gets closest to pi*a*b is the one that best matches theory, so we keep that.

  • Is an ellipse/circle of radius 1 just a point? Mathematics says no. A circle of radius zero is actually a point. Demonstrating this for a circle centered at the point (h,k), we would have:

    (x-h)^2 + (y-k)^2 = 0^2
    (x-h)^2 = -(y-k)^2
    x = h + sqrt(-(y-k)^2)

    ... which only has real solutions at x=h, y=k. So again, a point on screen corresponds to zero radius, in fact.

    If you want to fill a single pixel with a nonzero-radius-circle, your radius would need to be 0.5 in order to have a diameter of 1.

    For a radius of 1, you're now talking about a diameter of 2. At single-pixel resolution, this is again troublesome, because the next symmetric shape would be four pixels:

    **
    **

    which in fact has a radius of sqrt(2)=1.41... so we're simply fighting the properties of the computer screen at that point.

Alright, hope that satisfies a few questions on hand... as for whether we use the SQR version or the inner loop version is an interesting question. As a purist I like the SQR version rather than having a loop within a loop... It's just weird that SQR has been something to avoid in the past but miraculously now it's just as fast. Just weird...
« Last Edit: February 13, 2019, 06:45:37 pm by STxAxTIC »
You're not done when it works, you're done when it's right.

Offline STxAxTIC

  • Library Staff
  • Forum Resident
  • Posts: 1091
  • he lives
Re: Seeking best ellipse fill function. (For everyone's sake.)
« Reply #122 on: February 13, 2019, 07:52:33 pm »
Elaborating on the "area" trick...

So we're probably straining at gnats at this point. I came up with a test setup for counting the number of pixels in the ellipse to run it by the expected value. In the code below, I tuned a "fudge factor" to give the correct answer to within 0.08 pixels or so, but this is no reason to get excited. If you simply swap the a- and b- axes (rotate the ellipse 90 degrees), the area should still be the same right? Nope, it's off by 16 pixels for the same exact shape. Right away this tells me that we'll never get the precision we want on a screen without infinite resolution.

Needless to mention, the fudge factor doesn't work for any ellipse besides the test case, so I think our level of pedantic-ness can stop right around here.

Here's my test setup for that:

Code: QB64: [Select]
  1. SCREEN _NEWIMAGE(800, 600, 32)
  2. aaa = 75 ' SWAP THESE TO TEST
  3. bbb = 150
  4.  
  5. CALL FlatEllipseFill(200, 200, aaa, bbb, _RGBA(100, 100, 100, 100))
  6.  
  7. area = 0
  8. FOR i = 1 TO _WIDTH - 1
  9.     FOR j = 1 TO _HEIGHT - 1
  10.         IF POINT(i, j) <> 0 THEN area = area + 1
  11.     NEXT
  12. PRINT area - _PI * aaa * bbb
  13.  
  14. SUB FlatEllipseFill (ox AS INTEGER, oy AS INTEGER, a AS INTEGER, b AS INTEGER, col AS _UNSIGNED LONG)
  15.     IF a = 0 OR b = 0 THEN EXIT SUB
  16.     DIM h2 AS _INTEGER64
  17.     DIM w2 AS _INTEGER64
  18.     DIM h2w2 AS _INTEGER64
  19.     DIM x AS INTEGER
  20.     DIM y AS INTEGER
  21.     w2 = a * a
  22.     h2 = b * b
  23.     h2w2 = h2 * w2
  24.     LINE (ox - a, oy)-(ox + a, oy), col, BF
  25.     DO WHILE y < b
  26.         y = y + 1
  27.         x = SQR((h2w2 - y * y * w2) \ h2) - .45 ' FUDGE FACTOR
  28.         LINE (ox - x, oy + y)-(ox + x, oy + y), col, BF
  29.         LINE (ox - x, oy - y)-(ox + x, oy - y), col, BF
  30.     LOOP
  31.  

In conclusion, after fiddling with this for a second, we should just draw what looks good.
« Last Edit: February 13, 2019, 08:00:56 pm by STxAxTIC »
You're not done when it works, you're done when it's right.

Offline STxAxTIC

  • Library Staff
  • Forum Resident
  • Posts: 1091
  • he lives
Re: Seeking best ellipse fill function. (For everyone's sake.)
« Reply #123 on: February 14, 2019, 09:34:47 am »
Going once, going twice... SOLD on regular ellipses and circles.

One last question for bplus, about the modified tilted ellipse routine... Do we still need the first argument in this function? It's not referenced inside the SUB at all.

Code: QB64: [Select]
  1. SUB TiltedEllipseFill (destHandle&, ox, oy, a, b, ang, col AS _UNSIGNED LONG)
  2.     DIM max AS INTEGER, mx2 AS INTEGER, i AS INTEGER, j AS INTEGER
  3.     DIM prc AS _UNSIGNED LONG
  4.     prc = _RGB32(255, 255, 255, 255)
  5.     IF a > b THEN max = a + 1 ELSE max = b + 1
  6.     mx2 = max + max
  7.     tef& = _NEWIMAGE(mx2, mx2)
  8.     _DEST tef&
  9.     _SOURCE tef& 'point wont read without this!
  10.     FOR k = 0 TO 6.2832 + .05 STEP .1
  11.         i = max + a * COS(k) * COS(ang) + b * SIN(k) * SIN(ang)
  12.         j = max + a * COS(k) * SIN(ang) - b * SIN(k) * COS(ang)
  13.         IF k <> 0 THEN
  14.             LINE (lasti, lastj)-(i, j), prc
  15.         ELSE
  16.             PSET (i, j), prc
  17.         END IF
  18.         lasti = i: lastj = j
  19.     NEXT
  20.     DIM xleft(mx2) AS INTEGER, xright(mx2) AS INTEGER, x AS INTEGER, y AS INTEGER
  21.     FOR y = 0 TO mx2
  22.         x = 0
  23.         WHILE POINT(x, y) <> prc AND x < mx2
  24.             x = x + 1
  25.         WEND
  26.         xleft(y) = x
  27.         WHILE POINT(x, y) = prc AND x < mx2
  28.             x = x + 1
  29.         WEND
  30.         WHILE POINT(x, y) <> prc AND x < mx2
  31.             x = x + 1
  32.         WEND
  33.         IF x = mx2 THEN xright(y) = xleft(y) ELSE xright(y) = x
  34.     NEXT
  35.     _DEST destHandle&
  36.     FOR y = 0 TO mx2
  37.         IF xleft(y) <> mx2 THEN LINE (xleft(y) + ox - max, y + oy - max)-(xright(y) + ox - max, y + oy - max), col, BF
  38.     NEXT
  39.     _FREEIMAGE tef&
You're not done when it works, you're done when it's right.

Offline bplus

  • Global Moderator
  • Forum Resident
  • Posts: 8053
  • b = b + ...
Re: Seeking best ellipse fill function. (For everyone's sake.)
« Reply #124 on: February 14, 2019, 10:17:13 am »
Going once, going twice... SOLD on regular ellipses and circles.

One last question for bplus, about the modified tilted ellipse routine... Do we still need the first argument in this function? It's not referenced inside the SUB at all.

Code: QB64: [Select]
  1. SUB TiltedEllipseFill (destHandle&, ox, oy, a, b, ang, col AS _UNSIGNED LONG)
  2.     DIM max AS INTEGER, mx2 AS INTEGER, i AS INTEGER, j AS INTEGER
  3.     DIM prc AS _UNSIGNED LONG
  4.     prc = _RGB32(255, 255, 255, 255)
  5.     IF a > b THEN max = a + 1 ELSE max = b + 1
  6.     mx2 = max + max
  7.     tef& = _NEWIMAGE(mx2, mx2)
  8.     _DEST tef&
  9.     _SOURCE tef& 'point wont read without this!
  10.     FOR k = 0 TO 6.2832 + .05 STEP .1
  11.         i = max + a * COS(k) * COS(ang) + b * SIN(k) * SIN(ang)
  12.         j = max + a * COS(k) * SIN(ang) - b * SIN(k) * COS(ang)
  13.         IF k <> 0 THEN
  14.             LINE (lasti, lastj)-(i, j), prc
  15.         ELSE
  16.             PSET (i, j), prc
  17.         END IF
  18.         lasti = i: lastj = j
  19.     NEXT
  20.     DIM xleft(mx2) AS INTEGER, xright(mx2) AS INTEGER, x AS INTEGER, y AS INTEGER
  21.     FOR y = 0 TO mx2
  22.         x = 0
  23.         WHILE POINT(x, y) <> prc AND x < mx2
  24.             x = x + 1
  25.         WEND
  26.         xleft(y) = x
  27.         WHILE POINT(x, y) = prc AND x < mx2
  28.             x = x + 1
  29.         WEND
  30.         WHILE POINT(x, y) <> prc AND x < mx2
  31.             x = x + 1
  32.         WEND
  33.         IF x = mx2 THEN xright(y) = xleft(y) ELSE xright(y) = x
  34.     NEXT
  35.     _DEST destHandle&
  36.     FOR y = 0 TO mx2
  37.         IF xleft(y) <> mx2 THEN LINE (xleft(y) + ox - max, y + oy - max)-(xright(y) + ox - max, y + oy - max), col, BF
  38.     NEXT
  39.     _FREEIMAGE tef&

Sure it is, and it is vital. Just before drawing the lines this is set in code:
Code: QB64: [Select]
  1.     _DEST destHandle&
The sub works in isolated area to draw the outline and then calc the left and right boundaries of the interior line by line.
It then draws those lines at the destination.

Here is a demo app:
Code: QB64: [Select]
  1. _TITLE "Tilted Ellipse app" ' B+ 2019-02-12
  2.  
  3. CONST xmx = 640
  4. CONST ymx = 640
  5. SCREEN _NEWIMAGE(xmx, ymx, 32)
  6. _SCREENMOVE 340, 40
  7. c = xmx / 2
  8. FOR r = 210 TO 0 STEP -30
  9.     stepper = stepper + 30
  10.     offset = offset - _PI(2 / 24)
  11.     FOR a = 0 TO 2 * _PI - .001 STEP _PI(2 / 12)
  12.         x = c + r * COS(a + offset)
  13.         y = c + r * SIN(a + offset)
  14.         k = _RGBA32(0, 0, 200, 15)
  15.         TiltedEllipseFill 0, x, y, 250 - stepper, stepper, a + offset, k
  16.         _LIMIT 12
  17.     NEXT
  18.  
  19. SUB TiltedEllipseFill (destHandle&, x0, y0, a, b, ang, c AS _UNSIGNED LONG)
  20.     DIM max AS INTEGER, mx2 AS INTEGER, i AS INTEGER, j AS INTEGER
  21.     DIM prc AS _UNSIGNED LONG
  22.     prc = _RGB32(255, 255, 255, 255)
  23.     IF a > b THEN max = a + 1 ELSE max = b + 1
  24.     mx2 = max + max
  25.     tef& = _NEWIMAGE(mx2, mx2)
  26.     _DEST tef&
  27.     _SOURCE tef& 'point wont read without this!
  28.     FOR k = 0 TO 6.2832 + .05 STEP .1
  29.         i = max + a * COS(k) * COS(ang) + b * SIN(k) * SIN(ang)
  30.         j = max + a * COS(k) * SIN(ang) - b * SIN(k) * COS(ang)
  31.         IF k <> 0 THEN
  32.             LINE (lasti, lastj)-(i, j), prc
  33.         ELSE
  34.             PSET (i, j), prc
  35.         END IF
  36.         lasti = i: lastj = j
  37.     NEXT
  38.     DIM xleft(mx2) AS INTEGER, xright(mx2) AS INTEGER, x AS INTEGER, y AS INTEGER
  39.     FOR y = 0 TO mx2
  40.         x = 0
  41.         WHILE POINT(x, y) <> prc AND x < mx2
  42.             x = x + 1
  43.         WEND
  44.         xleft(y) = x
  45.         WHILE POINT(x, y) = prc AND x < mx2
  46.             x = x + 1
  47.         WEND
  48.         WHILE POINT(x, y) <> prc AND x < mx2
  49.             x = x + 1
  50.         WEND
  51.         IF x = mx2 THEN xright(y) = xleft(y) ELSE xright(y) = x
  52.     NEXT
  53.     _DEST destHandle&
  54.     FOR y = 0 TO mx2
  55.         IF xleft(y) <> mx2 THEN LINE (xleft(y) + x0 - max, y + y0 - max)-(xright(y) + x0 - max, y + y0 - max), c, BF
  56.     NEXT
  57.     _FREEIMAGE tef&
  58.  
  59.  
Tilted Ellipse app.PNG


After playing around trying to remove Dot at top and bottom, I have decided CircleFill draws a much more pleasing symmetric circle without dots and slightly faster than best FlatEllipseFill. If you try a CIRCLE overlap test over CircleFill you will see overlap all the way around the edge or mostly. If you do a CIRCLE overlap test for FlatEllipseFill, you will see a dotted border overlap all the way around the edge ie not such a good fit. Therefore, CircleFill is staying in my tool box.

You can do FlatEllipse with CIRCLE sub but I doubt the outline would fit our best FlatEllipseFill, therefore FlatEllipseFill will need a partner FlatEllipse sub or a switch to do just the outlines, I favor the latter, one sub with a switch for filling or not.

In my opinion QB64 should be doing these things with Circle as it does with LINE with an "F" switch, THEN all that would be needed is what we have for TiltedEllipse with an tfFill switch.

I wonder what the code for CIRCLE looks like from under-the-hood, how hard would it be to update that?





Offline SMcNeill

  • QB64 Developer
  • Forum Resident
  • Posts: 3972
    • Steve’s QB64 Archive Forum
Re: Seeking best ellipse fill function. (For everyone's sake.)
« Reply #125 on: February 14, 2019, 10:49:08 am »
One thing: It needs to preserve and restore the DEST and SOURCE to pre-execution settings:

Code: QB64: [Select]
  1. SUB TiltedEllipseFill (destHandle&, ox, oy, a, b, ang, col AS _UNSIGNED LONG)
  2.     DIM max AS INTEGER, mx2 AS INTEGER, i AS INTEGER, j AS INTEGER
  3.     DIM prc AS _UNSIGNED LONG
  4.  
  5.     DIM D AS INTEGER, S AS INTEGER 'to preserve old settings
  6.     D = _DEST: S = _SOURCE
  7.  
  8.     prc = _RGB32(255, 255, 255, 255)
  9.     IF a > b THEN max = a + 1 ELSE max = b + 1
  10.     mx2 = max + max
  11.     tef& = _NEWIMAGE(mx2, mx2)
  12.     _DEST tef&
  13.     _SOURCE tef& 'point wont read without this!
  14.     FOR k = 0 TO 6.2832 + .05 STEP .1
  15.         i = max + a * COS(k) * COS(ang) + b * SIN(k) * SIN(ang)
  16.         j = max + a * COS(k) * SIN(ang) - b * SIN(k) * COS(ang)
  17.         IF k <> 0 THEN
  18.             LINE (lasti, lastj)-(i, j), prc
  19.         ELSE
  20.             PSET (i, j), prc
  21.         END IF
  22.         lasti = i: lastj = j
  23.     NEXT
  24.     DIM xleft(mx2) AS INTEGER, xright(mx2) AS INTEGER, x AS INTEGER, y AS INTEGER
  25.     FOR y = 0 TO mx2
  26.         x = 0
  27.         WHILE POINT(x, y) <> prc AND x < mx2
  28.             x = x + 1
  29.         WEND
  30.         xleft(y) = x
  31.         WHILE POINT(x, y) = prc AND x < mx2
  32.             x = x + 1
  33.         WEND
  34.         WHILE POINT(x, y) <> prc AND x < mx2
  35.             x = x + 1
  36.         WEND
  37.         IF x = mx2 THEN xright(y) = xleft(y) ELSE xright(y) = x
  38.     NEXT
  39.     _DEST destHandle&
  40.     FOR y = 0 TO mx2
  41.         IF xleft(y) <> mx2 THEN LINE (xleft(y) + ox - max, y + oy - max)-(xright(y) + ox - max, y + oy - max), col, BF
  42.     NEXT
  43.     _DEST D: _DEST S 'restore those old settings
  44.     _FREEIMAGE tef&
  45.  


  These lines seem odd to me:

        WHILE POINT(x, y) = prc AND x < mx2
            x = x + 1
        WEND
        WHILE POINT(x, y) <> prc AND x < mx2
            x = x + 1
        WEND

Isn't this a case of WHILE x < mx 2 ??

If POINT(x,y) = prc then we increment x... If POINT(x,y) <> prc then we increment x...  Is there even a need for those checks?
https://github.com/SteveMcNeill/Steve64 — A github collection of all things Steve!

Offline STxAxTIC

  • Library Staff
  • Forum Resident
  • Posts: 1091
  • he lives
Re: Seeking best ellipse fill function. (For everyone's sake.)
« Reply #126 on: February 14, 2019, 11:05:59 am »
Crap, you raise an excellent point about having having shapes that are *not* filled. This is super easy to deal with - the reason I exclaim thusly is that nobody raised that idea til now.

EDIT

On second thought, the only shape not inherently "covered" (no pun) in QB64 is the un-filled, tilted ellipse. It covers all the rest.
« Last Edit: February 14, 2019, 11:22:00 am by STxAxTIC »
You're not done when it works, you're done when it's right.

Offline bplus

  • Global Moderator
  • Forum Resident
  • Posts: 8053
  • b = b + ...
Re: Seeking best ellipse fill function. (For everyone's sake.)
« Reply #127 on: February 14, 2019, 11:23:56 am »
Yes, I guess since the sub changes Source and Dest, it does need to be changed back, good catch Steve. I guess I didn't get caught because I never drew anything other than TiltedEllipseFills in my demo.

Steve:
Quote
  These lines seem odd to me:

I am sure they may seem odd to anyone, who hasn't tried drawing the lines at angles = yuck!

In order to have a pretty filled titled ellipse without overlap nor holes, you have to draw either vertical or horizontal lines or if you are really good, draw non overlapping boxes (which I think Vince attempted at one point).

To do this I used STATIC's formula's to draw the ellipse in an isolated area.
Then I went from top to bottom down the y axis and with the help of POINT found the left and right edge of the ellipse along the flat line. This is why the ellipse had to be drawn in an isolated area, so POINT only finds the ellipse points.

With the edges detected along flat lines we can draw a clean,no hole, no overlapping Tilted Ellipse Fill, at the place designated at destHandle&.

This is the code block that is finding the left and right edges of the tilted ellipse drawn in the isolated area:
Code: QB64: [Select]
  1.     DIM xleft(mx2) AS INTEGER, xright(mx2) AS INTEGER, x AS INTEGER, y AS INTEGER
  2.     FOR y = 0 TO mx2
  3.         x = 0
  4.         WHILE POINT(x, y) <> prc AND x < mx2
  5.             x = x + 1
  6.         WEND
  7.         xleft(y) = x
  8.         WHILE POINT(x, y) = prc AND x < mx2
  9.             x = x + 1
  10.         WEND
  11.         WHILE POINT(x, y) <> prc AND x < mx2
  12.             x = x + 1
  13.         WEND
  14.         IF x = mx2 THEN xright(y) = xleft(y) ELSE xright(y) = x
  15.     NEXT
  16.  

You have to find the edges on the same line and you have 3 cases:
1. no edge
2. the left and right edge are the same
3. the left and right edge are different

The added condition
 AND x < mx2
keeps x inside the bounds of the isolated drawing area when one or no POINTs are found.

Finally, when you go to draw the actual lines, you must make sure xLeft(y) is not at the right boundry ie no point of the ellipse was found for that y value.
« Last Edit: February 14, 2019, 11:39:05 am by bplus »

Offline STxAxTIC

  • Library Staff
  • Forum Resident
  • Posts: 1091
  • he lives
Re: Seeking best ellipse fill function. (For everyone's sake.)
« Reply #128 on: February 14, 2019, 11:38:44 am »
A very quick aside:

bplus is right about the inherent CIRCLE command (with eccentricity) not perfectly agreeing without our results. The difference is SO minuscule that our algorithms should probably not change though. Check out this simple mod that lets you send two colors to the ellipse function, with one color being just for the outline. We won't be keeping this of course:

Code: QB64: [Select]
  1. ' Video settings, Global declarations:
  2.  
  3. SCREEN _NEWIMAGE(800, 600, 32)
  4.  
  5. FOR k = 1 TO 100
  6.     CALL EllipseFill(320, 240, 250, 175, _RGBA(0, 0, 255, 128), _RGBA(0, 255, 0, 128))
  7.  
  8. ' FUNCTIONs and/or SUBs:
  9.  
  10. SUB EllipseFill (ox AS INTEGER, oy AS INTEGER, a AS INTEGER, b AS INTEGER, col1 AS _UNSIGNED LONG, col2 AS _UNSIGNED LONG)
  11.     '  ox  = center x coordinate
  12.     '  oy  = center y coordinate
  13.     '   a  = semimajor axis
  14.     '   b  = semiminor axis
  15.     ' col1 = outline color
  16.     ' col2 = fill color
  17.     IF a = 0 OR b = 0 THEN EXIT SUB
  18.     DIM h2 AS _INTEGER64
  19.     DIM w2 AS _INTEGER64
  20.     DIM h2w2 AS _INTEGER64
  21.     DIM x AS INTEGER
  22.     DIM y AS INTEGER
  23.     w2 = a * a
  24.     h2 = b * b
  25.     h2w2 = h2 * w2
  26.     LINE (ox - a, oy)-(ox + a, oy), col2, BF
  27.     DO WHILE y < b
  28.         y = y + 1
  29.         x = SQR((h2w2 - y * y * w2) \ h2)
  30.         LINE (ox - x, oy + y)-(ox + x, oy + y), col2, BF
  31.         LINE (ox - x, oy - y)-(ox + x, oy - y), col2, BF
  32.     LOOP
  33.     IF col1 <> col2 THEN CIRCLE (ox, oy), a, col1, , , b / a
  34.  

I suppose the a possible best solution it to just draw the thing, PAINT the inside like I did a few pages ago, and let the user place that on screen using image handles

EDIT

This will work fastest for the tilted case, as its our only option.

For nontilted things, I guess the challenge is back out there? Oh god...
« Last Edit: February 14, 2019, 11:49:53 am by STxAxTIC »
You're not done when it works, you're done when it's right.

Offline bplus

  • Global Moderator
  • Forum Resident
  • Posts: 8053
  • b = b + ...
Re: Seeking best ellipse fill function. (For everyone's sake.)
« Reply #129 on: February 14, 2019, 11:51:01 am »
Quote
I suppose the best solution it to just draw the thing, PAINT the inside like I did a few pages ago, and let the user place that on screen using image handles.

As I recall, we had discovered PAINT is slow and doesn't do alpha... I listed problems of PAINT way back in this thread. This is why  the Tilted Ellipse Fill routine jumps through so many hoops to avoid it!

Again I say, can we do something with QB64 CIRCLE routine ie add fills to what it already does?

Offline STxAxTIC

  • Library Staff
  • Forum Resident
  • Posts: 1091
  • he lives
Re: Seeking best ellipse fill function. (For everyone's sake.)
« Reply #130 on: February 14, 2019, 12:00:27 pm »
Quote
Again I say, can we do something with QB64 CIRCLE routine ie add fills to what it already does?

I defer you to [banned user] on that one...
« Last Edit: February 14, 2019, 12:01:28 pm by STxAxTIC »
You're not done when it works, you're done when it's right.

Offline bplus

  • Global Moderator
  • Forum Resident
  • Posts: 8053
  • b = b + ...
Re: Seeking best ellipse fill function. (For everyone's sake.)
« Reply #131 on: February 14, 2019, 12:24:43 pm »
OK maybe one of these days I will dig into the Source Code...

In meantime, I am keeping CircleFill in my tool box and IMO it should go in the forum's as the number 1 entry!

When I need an ellipse fill (and really how often is that?), I will use Titled Ellipse Fill (and no Fill switch?) because that code automatically includes the ability to do Flat Ellipses. This is the one with Steve's S and D fix.

If I really need speedier Flat Ellipses then STATIC's fudge of Pete's variation will do fine!

But I am trying to imagine Titled Ellipse No Fill, it could be draw directly to source no fooling around with isolated drawing. So build a switch onto Tilted Ellipse Fill or a whole separate sub? This is the question that remains for me because the requirements are so different.

« Last Edit: February 14, 2019, 12:31:47 pm by bplus »

Offline bplus

  • Global Moderator
  • Forum Resident
  • Posts: 8053
  • b = b + ...
Re: Seeking best ellipse fill function. (For everyone's sake.)
« Reply #132 on: February 14, 2019, 12:57:54 pm »
For the record, Titled Ellipse Fill does not compare well with CIRCLE with same radius as a and aspect b/a. Look at what happens when b exceeds a! but I am supposed to switch radius for CIRCLE when b > a.
Code: QB64: [Select]
  1. _TITLE "Tilted Ellipse Fill shape Study" ' B+ 2019-02-14
  2. 'compare to CIRCLE with aspect = a/b
  3.  
  4.  
  5. SCREEN _NEWIMAGE(1000, 700, 32)
  6. _SCREENMOVE 180, 20
  7.  
  8. FOR i = 0 TO 340 'draw ellipse at various heights and compare to CIRCLE with aspect i/300
  9.     CLS
  10.     PRINT "b Radius"; i; "   press any to get to 400, <backspace> to go back one, <esc> for next test."
  11.  
  12.     TiltedEllipseFill 0, 500, 350, 300, i, 0, _RGBA(255, 255, 255, 100)
  13.     IF i <> 0 THEN CIRCLE (500, 350), 300, _RGBA(255, 255, 255, 100), , , i / 300
  14.     k$ = ""
  15.     WHILE LEN(k$) = 0: k$ = INKEY$: WEND
  16.     IF k$ = CHR$(8) THEN i = i - 2
  17.     IF k$ = CHR$(27) THEN EXIT FOR
  18.  
  19. SUB TiltedEllipseFill (destHandle&, ox, oy, a, b, ang, col AS _UNSIGNED LONG)
  20.     DIM max AS INTEGER, mx2 AS INTEGER, i AS INTEGER, j AS INTEGER
  21.     DIM prc AS _UNSIGNED LONG
  22.  
  23.     DIM D AS INTEGER, S AS INTEGER 'to preserve old settings
  24.     D = _DEST: S = _SOURCE
  25.  
  26.     prc = _RGB32(255, 255, 255, 255)
  27.     IF a > b THEN max = a + 1 ELSE max = b + 1
  28.     mx2 = max + max
  29.     tef& = _NEWIMAGE(mx2, mx2)
  30.     _DEST tef&
  31.     _SOURCE tef& 'point wont read without this!
  32.     FOR k = 0 TO 6.2832 + .05 STEP .1
  33.         i = max + a * COS(k) * COS(ang) + b * SIN(k) * SIN(ang)
  34.         j = max + a * COS(k) * SIN(ang) - b * SIN(k) * COS(ang)
  35.         IF k <> 0 THEN
  36.             LINE (lasti, lastj)-(i, j), prc
  37.         ELSE
  38.             PSET (i, j), prc
  39.         END IF
  40.         lasti = i: lastj = j
  41.     NEXT
  42.     DIM xleft(mx2) AS INTEGER, xright(mx2) AS INTEGER, x AS INTEGER, y AS INTEGER
  43.     FOR y = 0 TO mx2
  44.         x = 0
  45.         WHILE POINT(x, y) <> prc AND x < mx2
  46.             x = x + 1
  47.         WEND
  48.         xleft(y) = x
  49.         WHILE POINT(x, y) = prc AND x < mx2
  50.             x = x + 1
  51.         WEND
  52.         WHILE POINT(x, y) <> prc AND x < mx2
  53.             x = x + 1
  54.         WEND
  55.         IF x = mx2 THEN xright(y) = xleft(y) ELSE xright(y) = x
  56.     NEXT
  57.     _DEST destHandle&
  58.     FOR y = 0 TO mx2
  59.         IF xleft(y) <> mx2 THEN LINE (xleft(y) + ox - max, y + oy - max)-(xright(y) + ox - max, y + oy - max), col, BF
  60.     NEXT
  61.     _DEST D: _DEST S 'restore those old settings
  62.     _FREEIMAGE tef&
  63.  
  64.  

Offline STxAxTIC

  • Library Staff
  • Forum Resident
  • Posts: 1091
  • he lives
Re: Seeking best ellipse fill function. (For everyone's sake.)
« Reply #133 on: February 14, 2019, 01:09:49 pm »
I have to read the previous post in the reflection of a funhouse mirror to make sense of it...

Quote
OK maybe one of these days I will dig into the Source Code...

Here's what you do. Find every instance of CIRCLE in the qb64 source code, and make a copy of it - CIRCLE2 or whatever. As soon as you can use CIRCLE2 to completely replace circle, you're ready to do the filling and rename CIRCLE2 to whatever. If successful, the result will be your occult object and not much more unfortunately, it was decided long ago that we won't add this kind of stuff to the language itself until someone clearly and intelligently defines when to stop. That has never occurred and I doubt it will.

Quote
In meantime, I am keeping CircleFill in my tool box...

Based on the outline/pixels issue, I agree with this. Do you mind posting your freshest copy of the function? Be sure to nerf it down to handle just circles, which I imagine render without boobs.

Quote
...and IMO it should go in the forum's as the number 1 entry!

If the Librarian can figure out how to arrange posts alphabetically instead of by date, you may have your wish on this until an A- or B- named function claims the #1 spot.

Quote
If I really need speedier Flat Ellipses then STATIC's fudge of Pete's variation will do fine!

Something tells me you swapped the names here, but who's keeping track? Authors/contributors/useful testers will be credited in alphabetical order in the Toolbox forum. Whoever wants to do the research can click the link to this thread any they can see who worked on what.

Quote
But I am trying to imagine Titled Ellipse No Fill, it could be draw directly to source no fooling around with isolated drawing. So build a switch onto Tilted Ellipse Fill or a whole separate sub? This is the question that remains for me because the requirements are so different.

That's a great issue. I prefer our tooling stay as pure as possible, i.e. avoiding anything that brings in complexity with underscore commands, image handles, and all that, so long as it does the best job. (Just a weird preference.) Since unfilled ellipses are just PSET and LINE, I'm all about having two functions, one for filled, one for unfilled.
You're not done when it works, you're done when it's right.

Offline STxAxTIC

  • Library Staff
  • Forum Resident
  • Posts: 1091
  • he lives
Re: Seeking best ellipse fill function. (For everyone's sake.)
« Reply #134 on: February 14, 2019, 01:12:57 pm »
Quote
For the record, Titled Ellipse Fill does not compare well with CIRCLE with same radius as a and aspect b/a. Look at what happens when b exceeds a! but I am supposed to switch radius for CIRCLE when b > a.

Are you knocking down straw men intentionally, or just need some coffee?
You're not done when it works, you're done when it's right.