Introduction
Here is a Speedometer class, CSpeedoMeter
v1.0. I had been looking for a speedometer control out there for a while but I couldn�t find one. Then I decided to give it a try. I thought it would be pretty simple, using simple trigonometric calculation to do rotation. If you are wondering why you need a rotation calculation, imagine you are in front of your car's dashboard. When you press the pedal you will see something rotating and suddenly your car starts accelerating. Exactly, you need to rotate a needle!
Basically, my approach is to have the background of the speedometer as a bitmap. Unfortunately, to make the needle as a bitmap is a bit messy. There is not an easy way to rotate bitmap in GDI API. But, we can just draw the needle as a line. You only need to take care of two points, while you connect with a straight line. In fact, you are actually controlling only one point. That point will be rotated and a line segment will be drawn representing the needle at any particular speed. Simple enough!
The Simple Mathematics
To make it happen, you need to calibrate your Speedo's needle. I am assuming the 0 degree start from 6 o�clock. As with most of the real Speedo controls in a real car, the needle is initially set at about 7:00 o�clock direction (30 degree clock-wise from 6 o�clock. Our example however uses initial offset at 40 degree). Remember, one full circle would represent 360 degrees. If let�s say, we assume one degree will represent 1 km/h, then life is easy. For each 1 km/h delta, it will represent a rotation of 1 degree clock-wise.
Therefore, once we can calculate the rotation and are able to draw the needle at any particular angle, then that�s about it, a speedometer is not far away from your hand. We just need to make some assumptions. So, for example let�s say, updating the needle to 240 km/h, you need to rotate the needle by 240 degrees + offset. Remember we use offset = 40, which makes the rotation required to set the needle to 240 km/h, to 280 degrees. The basic formula is:
RotationAngle = OffsetAngle + NewSpeed;
I am sure it is simple enough to be understood, so I would just teach you how to use my control. Another thing worth mentioning is, don�t forget about drawing the appropriate background image that is consistent with your assumption. In my case, I created a bitmap with the 0 speed set at 40 degrees from 6 o�clock clock-wise. I know my bitmap is not the coolest in this planet, but to make a start I think it is not too bad, yeah!
Using the code
There are a few files you need to copy to your project directory. They are:-
- matrix2x2.h & matrix2x2.cpp
- vector2.h & vector2.cpp
- speedometer.h & speedometer.cpp
The matrix2x2 and vector2 are also written by me for doing the rotation stuff. They become so handy from time to time when I develop various projects. The speedometer class is obviously the core engine of the Speedo.
After you put them in your project directory, create a dialog MFC project and add the above files to the project. Then, just build the project. I am sure it will fail. Why? Because you haven�t linked your project with winmm.lib. Please do so by going to Project-><ProjectName> Properties�
Go to linker and add winmm.lib on Additional Dependencies field. Just wanna inform you, I use Visual Studio .NET 2003 to build the project. For VS 6, please refer to VS documentation on how to link libraries to your project.
Next, you need to create a static control on your dialog. Size it to 400x400 to fit my bitmap background. Add a control variable to the static control, say m_speedometer
. Then under your XXXDlg.h, change the type of m_speedmeter
control from CStatic
to CSpeedoMeter
. Don�t forget to add #include speedometer.h
at the top of your XXXDlg.h file to make sure it understands what CSpeedoMeter
does.
Wait a minute, you are still 2-3 steps away from using the control. The next step would be to initialize the speedometer. To do this, I prefer to create an initialization function in your XXXDlg
(in my demo example, it is CspeedoMeterDlg
) class, say void InitializeSpeedoMeter()
. Add a few lines of code to the function body to set the bitmap, needle thickness, and its color. You should call the initialization routine inside the OnInitDialog()
handler.
void CSpeedoMeterDlg::InitSpeedoMeter()
{
m_speedometer.SetBitmap(IDB_SPEEDOMETER);
m_speedometer.SetNeedleThickness(5);
m_speedometer.SetNeedleColor(RGB(255,0,0));
}
I am assuming that you know how to import a bitmap to your project. Otherwise, simply go to Project->Add Resource on the main menu, then import bitmap. Don�t forget to name the bitmap (e.g., IDB_SPEEDOMETER
). Last but not the least, call InitSpeedoMeter
in the OnInitDialog()
handler, just under
.
OK, now you are ready to use the control. One easy way to try the control is to add OnMouseWheel(�)
handler. Then based on the value of zDelta
, you update the speedometer speed through UpdateSpeed(float speed)
interface or Accelerationg(float delta)
interface. My demo, uses OnTimer(�)
handler to do a simple but interesting simulation.
Points of Interest
Doing graphics programming is always exciting because no matter what, you will play with math, and if you are lucky, you will play with physics. It is so cool!. Any, constructive input, comments and expression of interest can be sent to my email address.
History
- V1.0 - Working speedometer.