Circular arcs and tangent peculiarity
Post by Zaphod on Jan 10th, 2017, 1:51pm
I was recently trying to draw arcs with tangents using the BB4W graphics commands and had difficulty with offsets of one or two pixels. I naturally imagined that I was doing something wrong. But looking again and running some test programs I find that there is something strange going on.
I imagined that if I drew a box and put a circle in the middle then the circle would be tangential to the sides. That is not what happens!
What happens depends on the values you choose for your coordinates. Now just to be sure, I understand that BB4W graphics units are twice the pixel count so the numbers have to be even. Then since we are dealing with a mid point for the radius that implies that the bounding square has to be an odd number of pixels so that there is a definite pixel that is the mid point. See the first two circles where we have even pixel sided squares which is what we kind of gravitate towards when programming. How close you get depends on the numbers you choose which I am sure is due to integer arithmetic in the code.
So we make a square with an odd number of pixels, which should work, but the x and y coordinate behave differently and I had to change the y coordinate by 1 pixel to make it work.
See the various attempts and how some values get closer than others. The first two could never have worked as the sides are an even numbers of pixels,
Code: ORIGIN 100,100
MOVE 0,0
DRAW 0,500
DRAW 500,500
DRAW 500,0
DRAW 0,0
REM MOVE 250,250
REM MOVE 0,250
REM PLOT 165, 0, 252
CIRCLE 250,250,250
ORIGIN 700,100
MOVE 0,0
DRAW 0,496
DRAW 496,496
DRAW 496,0
DRAW 0,0
REM MOVE 248,248
REM MOVE 0,248
REM PLOT 165, 0, 250
CIRCLE 248,248,248
ORIGIN 1300,100
MOVE 0,0
DRAW 0,502
DRAW 502,502
DRAW 502,0
DRAW 0,0
REM MOVE 248,248
REM MOVE 0,248
REM PLOT 165, 0, 250
CIRCLE 252,250,252
So you would think the third circle should work with x=252, y=252
But you can try that and see it is shifted too high.
In the end I decided that BB4W graphics were unsuited to the task I had in hand and used the GDI+ library which has no such issues.
If anyone knows how to ensure that tangents are actually tangential with BB4W arcs, always, I would be interested to hear because I can't fathom it. And I was not trying something as simple as bounding squares but in joining different curves seamlessly by having a common tangent. In that I failed.
Re: Circular arcs and tangent peculiarity
Post by DDRM on Jan 10th, 2017, 4:57pm
Hi Zaphod,
I wonder if it relates to the issue described in "pixel-perfect graphics", with relation to FILLED shapes: that the Windows polygon function is used, and includes the top left, but not the bottom right point of the vertices.
I note that the previous section says outline shapes are inclusive (i.e. the area covered by the lines is one greater than the specified width and height), but that that paragraph mentions triangles, rectangles and parallelograms, but not circles, ellipses or arcs.
That would explain why your bounding box is a little bigger than the circle that should fit exactly within it?
Try adding this:
Code: ORIGIN 100,600
MOVE 250,250
MOVE 502,250 :REM Set right-hand edge 1 pixel further right than expected, since it will be omitted?
REM Arguably, it looks better ANOTHER pixel further right - not sure why - probably the coordinate of the arc never QUITE reaches the integer value
PLOT 165,250,500
MOVE 750,250
MOVE 500,250
PLOT 165,750,0
GCOL 3,1
LINE 500,0,500,500
GCOL 0,0
MOVE 250,750
MOVE 0,750
PLOT 165,252,-2 :REM Need to set this intersection point one pixel lower and one pixel further right
Don't know if that helps...
D
Re: Circular arcs and tangent peculiarity
Post by hellomike on Jan 10th, 2017, 7:16pm
Hi,
Is that the same peculiarity, that I encounter within the next program?
Code: order%=2
size=(2^order%-1)*4+2
h%=1024/size:PRINT "h% = ";h%
MOVE 400,200+h%
PROCsierpinski(order%)
END
DEF PROCsierpinski(n%)
PROCleft(n%) :PLOT1,h%,h%
PROCtop(n%) :PLOT1,h%,-h%
PROCright(n%) :PLOT1,-h%,-h%
PROCbottom(n%):PLOT1,-h%,h%
ENDPROC
DEF PROCleft(n%)
IF n%=0 ENDPROC
PROCleft(n%-1) :PLOT1,h%,h%
PROCtop(n%-1) :PLOT1,0,h%*2
PROCbottom(n%-1):PLOT1,-h%,h%
PROCleft(n%-1)
ENDPROC
DEF PROCtop(n%)
IF n%=0 ENDPROC
PROCtop(n%-1) :PLOT1,h%,-h%
PROCright(n%-1):PLOT1,h%*2,0
PROCleft(n%-1) :PLOT1,h%,h%
PROCtop(n%-1)
ENDPROC
DEF PROCright(n%)
IF n%=0 ENDPROC
PROCright(n%-1) :PLOT1,-h%,-h%
PROCbottom(n%-1):PLOT1,0,-h%*2
PROCtop(n%-1) :PLOT1,h%,-h%
PROCright(n%-1)
ENDPROC
DEF PROCbottom(n%)
IF n%=0 ENDPROC
PROCbottom(n%-1):PLOT1,-h%,h%
PROCleft(n%-1) :PLOT1,-h%*2,0
PROCright(n%-1) :PLOT1,-h%,-h%
PROCbottom(n%-1)
ENDPROC
When h% is an odd number (e.g. when order%=2), the shape doesn't correctly close.
See bottom left corner.
When I run the same program within RISCOS (BASIC V 1.29), the shape does close correctly!
Thanks
Mike
Re: Circular arcs and tangent peculiarity
Post by Zaphod on Jan 10th, 2017, 10:11pm
Hi, Mike,
It is related but not the same I think. Your problem is the simple fact that h% must be an even number so that it plots to a pixel. You are getting 'rounding' down to the lower pixel. A BB4W graphic maps to pixel that is h% DIV 2. With odd values of h% all sorts of weird stuff happens!
DDRM. Your curved plot is typical what I have seen. Just that one or two pixel out sometimes. To make matters worse my radius and angles of arcs are user inputs so individual tweaks can't be applied. Some inputs looked quite ratty and others just fine. Since computers are logical it must be something that can be defined. It is something to play with on snowy days.
Thanks for your comments and I will look at that Pixel Perfect bit again. I just find it very strange that with PLOT 165 you give it the center and a point on the curve, and then it draws it and the point isn't on the curve by 1 pixel. It looks as if there is a similar effect though if you do this with circles:
Code:
x%=500
y%=500
r%=204
CIRCLE x%,y%,r%
PRINT ~(TINT(x%,y%+r%)) :REM Top
PRINT ~(TINT(x%,y%-r%)) :REM Bottom
PRINT ~(TINT(x%-r%,y%)) :REM Left
PRINT ~(TINT(x%+r%,y%)) :REM Right
Where 2 results are what you expect and 2 aren't if r% is divisible by 4, and none of the 4 points are plotted if r% not divisible by 4
So lets make it not divisible by 4 and see what points are plotted.
Code: x%=500
y%=500
r%=202
CIRCLE x%,y%,r%
PRINT ~(TINT(x%,y%+r%)) :REM Top
PRINT ~(TINT(x%,y%-r%)) :REM Bottom
PRINT ~(TINT(x%-r%,y%)) :REM Left
PRINT ~(TINT(x%+r%,y%)) :REM Right
PRINT "-1"
PRINT ~(TINT(x%,y%+r%-2)) :REM Top
PRINT ~(TINT(x%,y%-r%+2)) :REM Bottom
PRINT ~(TINT(x%-r%+2,y%)) :REM Left
PRINT ~(TINT(x%+r%-2,y%)) :REM Right
PRINT "-2"
PRINT ~(TINT(x%,y%+r%-4)) :REM Top
PRINT ~(TINT(x%,y%-r%+4)) :REM Bottom
PRINT ~(TINT(x%-r%+4,y%)) :REM Left
PRINT ~(TINT(x%+r%-4,y%)) :REM Right
So the radius has to be divisible by 4 or you can be up to 2 pixels out, and smaller than you would think, whereas the RECTANGLE is shifted by 1 pixel according to the 'Pixel Perfect' topic. The search continues...
What fun?
UPDATE: It seems that with the radius divisible by 4 (BB4W Graphics units) the Top and Left side are where I would expect but the bottom and right are 1 pixel closer to the center. With a radius that is not divisible by 4 the circumference is an additional pixel closer to the center on the four quadrants. So top and left are -1, bottom and right are -2 pixels.
Now how do I use that information? Nah, GDI+ library still looks a better option.
Z
Re: Circular arcs and tangent peculiarity
Post by hellomike on Jan 14th, 2017, 9:21pm
Thanks.
I guess BASIC V rounds rather than truncates.
Regards,
Mike