DrawRect takes integers

I draw my own custom graph and the width of the graph can vary by monitor.

I calculate the width and the number of bars to draw and then calculate the width of each bar but I have to use Floor on the division in order to round to an integer value.

This is a problem because then the total width of all bars does NOT equal the total width of the graph… and so there is a big gap to the right. And the bars aren’t as wide as they could be.

Any reason why the graphics DrawRect and FillRect couldn’t use Double instead of Integer???


because graphics routines on a monitor are restricted to the pixel resolution of said monitor…

You can light up pixel(1,1) or pixel(2,2) but there is no such a thing as pixel(1.23,1.97)… but if done properly you should never be off by more that (# of bars)-1 pixels… and even so, you should use an algorithm that interpolates across your chart, meaning it adds a pixel or two to the width of some bars, which spreads the “error” across the entire screen instead of one big glaring gap.

example… you calculate the width to be 50.5 pixels
bar #1 is from 0 to 50, bar #2 is from 51 to 101, then 101 to 151, then 152 to 202 etc.

You should use Round instead of Floor. That will reduce the overall error. Then if you need to, spread the difference across the first few bars.

OK I guess this interpolation is not what I am doing… I am using this code to calc the width of each bar and then other code draws each bar with DrawRect and colors it with FillRect.

if (g.Width - (XintInc * numBars)) >= numBars Then
XintInc = XintInc + Floor((g.Width - (XintInc * numBars)) / numBars)
End If

This does leave a big gap on the right side of the bars.

When I did that the chart might not fit because rounding UP with 80 bars might leak over the right side of the chart width.

Each bar object should have its own width, so you can adjust them to fill the available space.

Note that when I have done this, I keep everything in doubles and round just before I call and draw functions. I assumed that’s what you were doing when I suggested rounding.

In my code everything is integer because that’s what the graphics routines want.

I could add 1 pixel to every other bar until it hits width of the graph or something.???

Do all your work in doubles

Take the width, divide it by the number of segments you want to come up with your segwidth and/or segheight values.

Then interate I from 0 to segnum

Multiply i by segwidth/height and round the result before drawing.

Your drawn segments will be slightly different widths but will likely look ok overall. The width will work out to the exact number you’re looking for because you started with it.

I’ve done this for a number of drawing applications and it works well.


The rule of thumb is don’t commit to pixels until the very last moment.

For OS X and iOS there is. All the underlying Core Graphics draw functions take floating point coordinates and when plotting curves the difference is noticeable.

you can sorta get at these subpixel coordinates in Xojo by playing with ScaleXY. Set it to 0.1 and your draw coordinates now represent 1/10th pixel. In this code, because the effectively 1 pixel wide line is drawn between pixels it’s antialiased to cover 2 pixels wide at lower intensity.

[code]Sub Paint(g As Graphics, areas() As REALbasic.Rect)

g.ScaleX = 0.1
g.ScaleY = 0.1
g.PenWidth = 10 //1 pixel wide

g.ForeColor = &c000000
g.DrawRect(205, 205, 400, 400) //20.5, 20.5, 40, 40 effective pixel coordinates

End Sub

I’d go with Steve’s idea for drawing a bar graph though. You probably don’t want ant-aliasing so they’d have to land on pixels anyways.

OS X’s Core Graphics drawing uses floating point values, and so does the new framework xojo.core.rect, core.size and core.point.

However CGImage uses integers, because they’re bitmap images :slight_smile:

Yeah, this is basically how it’s done.

For 6 bars and 122 pixels of width (example of course) that won’t divide evenly. So first, start with the minimum bar width:

Const NumBars = 6 Const AvailableWidth = 122 Dim BarWidth As Integer = Floor(AvailableWidth / NumBars) // 20

Then find the remainder

Dim RemainingPixels As Integer = AvailableWidth - (NumBars * BarWidth) // 2

What this RemainingPixels variable tells us is the number of bars that need 1 additional pixel. So in this example, the first 2 bars will need 1 extra pixel. Bars 1 and 2 should be 21, while 3-6 should be 20.

actually… no… while the IOS graphics routines take floating point values, the hardware is still “integer”… it just removes the burden of the calculations we are discussing away from the developer

Well, this is an example where having double the amount of pixels with HiDPI support can make things significantly easier. Not exactly fractional pixels, but there are indeed two pixels per “1/72th inch” point.

Dave No, fractional positions ARE supported and they are represented by grey scale or intensity variations. Look closely at small fonts and you can see the effect of fractional pixels.

Anti Aliasing is NOT fractional pixels. It is a way to reduce jaggies and give an impression of smoothness by blurring somewhat the edge of oblique lines and curves. In Windows Cleartype, in addition to grey pixels, yellow and blue ones are used to improve legibility by color contrast.

You can select subpixel positioning for text via declare into the CGContext object of iOS and OS X. But it’s not enabled by default.

[quote=264557:@Ulrich Bogun]You can select subpixel positioning for text via declare into the CGContext object of iOS and OS X. But it’s not enabled by default.

CGContextSetAllowsFontSubpixelPositioning is allowed only if the font is antialiased, so indeed some blurry rendition can produce an image of text that looks like at a fraction of the pixel.

But yet, in the example of the OP, there is no way to draw half a pixel in a graph.

Michel: Fractional text positioning results in use of antialiasing. Yes they are different things but they both DO exist.