Click here to Skip to main content
15,886,067 members
Please Sign up or sign in to vote.
1.00/5 (1 vote)
Hello,

I am trying to draw a 2D graph using the following range : X( 0 - 3051) and Y( 200,000 - 350,000). What is the best way to convert these into coordinates relating to the picture control that has dimensions (top: 192, left: 11, bottom: 593, Right: 758).
I have been trying to get my range properly but the conversion from int to float is making it really complicated. Below is my code. Could you please let me know what is wrong and how can I best approach this?

C++
CDC* pDC =  &argDc;
CBrush* pOldBrush = pDC->GetCurrentBrush();
CPen* pOldPen = pDC->GetCurrentPen();

CRect rectClient;
m_GraphWindowCtrl.GetWindowRect(&rectClient);
ScreenToClient(&rectClient);

int GraphXRange = rectClient.Width();
int GraphYRange = rectClient.Height();

double ScreenXSeconds = (double)rectClient.Width() / m_ScreenXMeters; // 3051
double ScreenYGain = (double)rectClient.Height() / m_ScreenYMeters; // 350,000 - 200,000 = 150,000

Brush brush;
CBrush* pBrush;
brush.CreateSolidBrush(RGB(0,255,0));
pBrush = pDC->SelectObject(&brush);

CRect txtRectX,txtRectY;
CPen pen;
CPen* pPen;
pen.CreatePen(PS_SOLID | PS_COSMETIC, 1, RGB(255,0,0));
pPen = pDC->SelectObject(&pen);
pDC->MoveTo(rectClient.TopLeft());


Looking forward to some suggestions. I am quite confused with the logical to screen coordinates theory.
Posted
Updated 2-Apr-13 4:37am
v2

You did actually all that is necessary for your own coordinate calculation, assuming you leave the windows viewport in its native (text) mode. The two factors ScreenXSeconds and ScreenYGain are the factors with which you have to multiply the raw values. The names chosen are not to my liking, but that's another story. For the sake of our discussion, lets call them scaleX and scaleY. Then you would calculate the screen coordinates for raw point (rx, ry):
C++
double scaleX = rectClient.Width() / 3051.;
double scaleY = rectClient.Height() / 150000.;
...
int x = int (scaleX * rx) + rectClient.left;
int y = int (scaleY * ry) + rectClient.top;

If you want ot have the y-axis grow from bottom to top (as most people do) you need to modify that slightly:
C++
int y = int (scaleY * -ry) + rectClient.bottom;

Instead of switching between integer and double arithmetic back and forth, there is also a pure integer way of doing this:
C++
int x = MulDiv (rx, rectClient.Width(), 3051) + rectClient.left;
int y = MulDiv (-ry, rectClient.Height(), 150000) + rectClient.bottom;

If speed is an issue, the latter version is probably preferrable. The floating point unit in our modern processors is lightning fast. BUT: The conversion between integer and floating point and back and particular any rounding is a relatively slow operation. So one is well advised to stay in the integer or the floating point world whenever possible and avoid cross overs.
 
Share this answer
 
Comments
H.Brydon 2-Apr-13 15:46pm    
I hope you like all those +5's I've been handing out lately... :-)
nv3 2-Apr-13 15:50pm    
I sure appreciate them, H.Brydon. As I do your contribution to this website.
Mobile.Instinct 3-Apr-13 4:41am    
Seriously thanks a lot for your answer and that special MulDiv trick. I never knew that existed.
nv3 3-Apr-13 4:46am    
You're welcome.
 
Share this answer
 
Comments
Mobile.Instinct 2-Apr-13 11:48am    
Hello, could you please give an example on how could use it in my situation? It seems to be quite easy but I'm really struggling to get this bit working. Looking forward to your reply.

Thanks.
Style-7 2-Apr-13 12:00pm    
Use this cool book, see chapter 5 The GDI Mapping Mode with examples
http://share.auditory.ru/2008/Dmitry.Boldyrev/Books/WinAPI/Programming%20Windows%20-%20Win32%20Api%20(Mspress,%20Charles%20Petzold,%205Th%20Ed).pdf

This content, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)



CodeProject, 20 Bay Street, 11th Floor Toronto, Ontario, Canada M5J 2N8 +1 (416) 849-8900