views:

258

answers:

7

Hi to all,

i've encountered a little problem that i can't find answer to, so i hope to find someone here to help me.

So this is the problem. I have a buffer with real numbers (float) that i need to draw on my scope. I implemented a class that can draw integers only and i really don't know how to do that with float numbers as i don't know how to draw their decimal part. Drawing is done with GDI (MoveTo(), LineTo()) and these functions are capable of taking only integer coordinates. So, if anyone would know the solution ...

I'm using c++ within C++ Builder 2009 IDE.

Thanks,

Adi

A: 

You'll have to convert them to integers and then pass them to functions like MoveTo() and LineTo().

kitchen
+2  A: 

What do these float values represent? I will assume they are some co-ordinates. You will need to know two things:

  • The source resolution (i.e. the dpi at which these co-ordinates are drawn)
  • The range that you need to address

After that, this becomes a problem of scaling the points to suitable integer co-ordinates (based on your screen-resolution).

Edit: A simple formula will be:

X(dst) = X(src) * DPI(dst) / DPI(src)

dirkgently
These floats are amplitudes of some signal (i.e. EEG) so i need to draw them on a time axis. Resolution could be any - that's sth that i will let user decide - i.e. if resolution is 3 pixels then the currently amplitude will be drawn on next 3 pixels.Concerning the range i'm still not quite sure which one will be but let's say it won't be much different than [-100, 100].Please can you give some example of scaling the points to integer coordinates. I was thinking of sth similar but still not sure how to do it. User kitchen can also give some comment up here :)Thank you
Adi
+4  A: 

At some point, they need to be converted to integers to draw actual pixels.

Generally speaking, however, you do not want to just cast each float to int, and draw -- you'll almost certainly get a mess. Instead, you need/want to scale the floats, then round the scaled value to an integer. In most cases, you'll want to make the scaling factor variable so the user can zoom in and out as needed.

Another possibility is to let the hardware handle most of the work -- you could use OpenGL (for one example) to render your points, leaving them as floating point internally, and letting the driver/hardware handle issues like scaling and conversion to integers. This has a rather steep cost up-front (learning enough OpenGL to get it to do anything useful), but can have a fairly substantial payoff as well, such as fast, hardware-based rendering, and making it relatively easy to handle some things like scaling and (if you ever need it) being able to display 3D points as easily as 2D.

Edit:(mostly response to comment): Ultimately it comes down to this: the resolution of a screen is lower than the resolution of a floating point number. For example, a really high resolution screen might display 2048 pixels horizontally -- that's 11 bits of resolution. Even a single precision floating point number has around 24 bits of precision. No matter how you do it, reducing 24-bit resolution to 12-bit resolution is going to lose something -- usually a lot.

That's why you pretty nearly have to make your scaling factor variable -- so the user can choose whether to zoom out and see the whole picture with reduced resolution, or zoom in to see a small part at high resolution.

Since sub-pixel resolution was mentioned: it does help, but only a little. It's not going to resolve a thousand different items that map to a single pixel.

Jerry Coffin
Cool this is a good answer. Yes, I could use DirectDraw as i have some experience with it but if i wanted to scale it manually how would you do it on a value for example 35.78?If i scale it with a scaling factor 1.2 that would be 35.78*1.2=42.936 so let's say i would round it to 43. But what happens when i want to scale value 35.8? That with the same scaling factor gives again 43. What about a resolution?Thanks
Adi
@Adi: If you want to draw with a subpixel resolution use OpenGL/D3D with anti-aliasing, or WPF or something similar.
Marcus Lindblom
A: 

Scale. For example, multiply all the integral values by 10. Multiply the floating point values by 10.0 and then truncate or round (your choice). Now plot as normal.

This will give you extra precision in your graphing. Just remember the scale factor when you look at the picture.

Otherwise convert the floats to int before plotting.

Thomas Matthews
A: 

Ok. But all that you're proposing guys doesn't seem to be a good solution or i'm missing something.

Let's say i have a plot area of height 100 pixels. That means that i have 100 discrete levels to draw a point onto. But if my maximum amplitude is 100 and if it is real number, that means that i have an "infinite" set of possible values on interval [0, 100]. The problem is in losing information (that decimal part) while mapping real values to integer representatives.

Particularly if we have buffer with amplitudes: 35.78 35.8 35.85 35.87. If i scale them with, let's say, factor 10.00 we get the following: 357.8 358.0 358.5 358.7. Then i if wanted to draw them i need to get them back to integers - let's say using round(). Final result is: 358 358 358 359 which i again need to rescale it to fit onto the plot area. Without rescaling i would need to increase the size of plot area which doesn't seem to be a good solution.

I need somehow to get the right resolution and be able to draw original values. It seems that OpenGL provides a way to draw between pixels - on real coordinates.

Adi
A: 

You can try to use GDI+ instead GDI, it has functions that are using float coordinates.

Mikhail
A: 

Hm i was playing a little bit with OpenGL and GDI+ and conclusion is that with non-scaled (factor=1) values you can't plot with float precision. But when you scale it with some factor!=1 you can get displayed those values regularly.

Still problem remains if you have to plot values that are similar enough (i.e. 10.0 10.1 10.2 10.3 10.4 ...). If scaling factor is 1.0 then in this situation you will get graph as if all values were 10.0. Solution is to increase scaling factor enough so you can see these minor changes. In GDI+ ScaleTransform() gets that job done. At first i didn't think that this is how it is done. It seemed to me very strange that if i wanted to see the graph in all its volume that i had to zoom first.

Thank you all for your help :)

Adi