April 16, 2024, 01:10:32 PM

News:

IonicWind Snippit Manager 2.xx Released!  Install it on a memory stick and take it with you!  With or without IWBasic!


19c. Drawing the Background

Started by LarryMc, September 13, 2011, 10:46:39 AM

Previous topic - Next topic

0 Members and 1 Guest are viewing this topic.

LarryMc

Part C

Next we will draw tic marks on the various gages.  But, before we can proceed we need to do a little review.

We have been drawing in a 200 x 200 pixel square with its center at 100,100.  So far, we have been using the GdipDrawArc function to draw arcs / circles with their centers located at 100,100.  The exceptions have been the ROUND2PENH and ROUND2PENV style gages.  With them the calculations were based on larger squares with a different center.  But even they were repositioned, relative to the center of our 200 x 200 square.  And all were drawn based upon a starting angle and an ending angle or total degrees of arc sweep.

We had mention earlier that GDI+ angles have a zero degree point at the 3:00 o'clock position.  From that point angles increase in a CW direction and decrease in a CCW direction.

Tic marks for our gages are like spokes on a wheel. All are straight lines connected to the outer ring (and perpendicular to the tangent at that point) and go to the center of the circle. Any point we pick along the length of a spoke is at the same angle as all other points along the spoke.  So, with the right techniques, we can draw tic marks that start at a specified angle on the arc then head straight toward the center of the circle but are stopped after just a few pixels are drawn.

We're going to be drawing short lines as tic marks.  In order to draw a line we need to know the x,y coordinates to start and the x,y coordinates to stop.  What we have to work with is the angles of our arcs / circles and we know the radius they were drawn on (because we just got through drawing them).  So the problem is how do we figure out what x, y coordinates to use.

Trigonometry is our solution.  With trig we know that on a circle with a radius of 1 and whose center point is at 0,0 the following is true for any given angle:
the y coordinate above or below the horizontal center point is equal to the sine of the angle [ y = sine(angle)].
the x coordinate left or right of the vertical center point is equal to the cosine of the angle [ x = cosine(angle)].

Since the sine / cosine functions are based upon a circle of radius 1 we simply need to multiply the values returned by the actual radius to get the correct x, y values.

In trig the angle can be expressed in radians or degrees.  IWBasic can handle both also but it has always been easier to deal with degrees.  So, where required, we will be using the SIND and COSD functions.

There's one little quirk that the reader should be aware of .  Both GDI+ and trig angle measurements start at the 3:00 o'clock position. The problem lies in the fact that GDI+ angles increase in the CW direction while with trig they increase in the CCW direction.  This alone would cause the polarity of our y coordinate to be the inverse of what it should be.  However, on the computer the y coordinates start at the top and  go down as they increase which is the reverse of the grid that trig uses.  So what we have is the equivalent of a double negative; the two quirks cancel each other out and we don't have to worry about them.

We the above knowledge we will start the coding for our tic marks.  The first thing we need to do is determine how far apart, in degrees, our main (or major ) tic marks should be. We also need the spacing for our minor tic marks.  We'll use the following code:

...
INT ticspace, tichalfspace
select #g_dat.sStyle
case ROUNDCLOCK12
ticspace=30
tichalfspace = 6
case ROUNDCLOCK24
ticspace=30
tichalfspace = 15
default
ticspace=(#g_dat.nAngleEnd -#g_dat.nAngleStart)/(#g_dat.nRangeMaxDial-#g_dat.nRangeMinDial)
tichalfspace = ticspace/2
endselect
...


In the above, we start by creating two variables to hold the spacing variables. We then add a SELECT block so we can separate the two special cases from the default.  With the ROUNDCLOCK12 type the major tics will be at 5 minute intervals which corresponds to the hours.  The minor tics will be a 1 minute intervals.  With the ROUNDCLOCK24 type the major tics will be at 2 hour intervals.  The minor tics will be a 1 hour intervals.

With the rest of the gage types we will use the start and ending points of the arc in degrees to get the span and then divide that my the calculated number of segments (based upon the difference in our dial range max/min values).  The result will give us the spacing for our major tics and taking half of that will give us our minor spacing.

Now that we have the spacing determined we can set up our SELECT block to handle the different way we go about drawing the tics.  We'll start with this structure:

...
int x
select #g_dat.sStyle
case ROUND2PENV

case ROUND2PENH

case ROUNDCLOCK12

default

endselect
...


The default  case will draw our main tics as discussed above. Then we will add a minor tic between each main tic.  The ROUNDCLOCK12 type is a special case because of instead of a single minor tic between each major tic there will be four; one for each minute.  The ROUND2PENV and  ROUND2PENV types are special cases because their major tic marks will more closely resemble the teeth on  a comb instead of the spokes in a wheel.  Also, those two types will not have minor tic marks.

We'll start with the default case:

...
default
'main
for x= int(#g_dat.nAngleStart) to int(#g_dat.nAngleEnd) step  ticspace
GdipDrawLine(pGraphics,pPen, COSD(x)*86 +100, SIND(x)*86+100, COSD(x)*73+100, SIND(x)*73+100)
next x
'minor
for x= int(#g_dat.nAngleStart)+ tichalfspace to int(#g_dat.nAngleEnd) step  ticspace
GdipDrawLine(pGraphics,pPen,COSD(x)*86 +100, SIND(x)*86+100,COSD(x)*78+100, SIND(x)*78+100)
next x
...


For the major tic marks we set up a FOR loop that starts at the start angle and increments by the major tic mark spacing until it reaches the end angle.  The GdipDrawLine function draws the tic marks.  Notice that both our beginning x,y and our ending x,y values have 100 added to them.  This is done to move the reference from the upper left corner of our control to the center of our 200 x200 pixel, as discussed earlier.  The beginning point of our tic lies on a circle with a radius of 86 pixel and the end point lies on a circle with a radius of 73 pixels.

The minor tic marks are drawn the same way as the major marks with two adjustments. The starting angle has the tichalfspace added to it so the minor marks will be centered between the major tic marks. Also, since we want these marks to be shorter we have increased the radius of the end point circle from 73 pixels to 78 pixels.

The ROUNDCLOCK12 case is addressed next.

...
case ROUNDCLOCK12
'main
for x= int(#g_dat.nAngleStart) to int(#g_dat.nAngleEnd) step  ticspace
GdipDrawLine(pGraphics,pPen,COSD(x)*86 +100, SIND(x)*86+100,COSD(x)*73+100, SIND(x)*73+100)
next x
'minor
for x= int(#g_dat.nAngleStart)+ tichalfspace to int(#g_dat.nAngleEnd) step  tichalfspace
GdipDrawLine(pGraphics,pPen, COSD(x)*86 +100, SIND(x)*86+100, COSD(x)*78+100, SIND(x)*78+100)
next x
...


The major tic marks are drawn exactly the same as for the default case.  The difference is in how we set up the FOR loop.  We adjust the start angle the same as before but instead of incrementing by the major tic spacing we use the tichalfspace.  With this arrangement, instead of having a single minor tic halfway between the major tics we will have 4, evenly spaced, minor tics.  This will give us the minute tics we are use to seeing on regular clocks.

Next is the ROUND2PENV case.

...
case ROUND2PENV
'main - left side
#g_dat.nAngleStart=20
#g_dat.nAngleEnd=-20
for x= int(#g_dat.nAngleStart) to int(#g_dat.nAngleEnd) step  -ticspace
GdipDrawLine(pGraphics,pPen, COSD(x)*220-133, SIND(x)*212+100, 92, SIND(x)*212+100)
next x
'main - right side
#g_dat.nAngleStart=160
#g_dat.nAngleEnd=200
for x= int(#g_dat.nAngleStart) to int(#g_dat.nAngleEnd) step  ticspace
GdipDrawLine(pGraphics,pPen, COSD(x)*220+333, SIND(x)*212+100, 108, SIND(x)*212+100)
next x
...


The first thing we notice different is that we're having to reassign values to our start and ending angles.  That's because we need to use the variables twice in this section of code.  Once for the left side and once for the right side.  The FOR loops are structured the same as was previously done.  The starting point coordinates line on the circle we creating through trial and error earlier.  But our end points are calculated differently.  Instead of being a point on a circle they are drawn as horizontal lines with a constant end point.  This will give the appearance of teeth on a comb.  The total result is that we will have a column between the left and right tic marks which we will use for a common set of scale numbers.

The  ROUND2PENH case follows the same pattern as the  ROUND2PENV case except that the tic marks are drawn as vertical lines. This results in a row space between the top and bottom sections where the scale numbers will be placed.  The code is as follows:

...
case ROUND2PENH
'main - top side
#g_dat.nAngleStart=-250
#g_dat.nAngleEnd=-290
for x= int(#g_dat.nAngleStart) to int(#g_dat.nAngleEnd) step  -ticspace
GdipDrawLine(pGraphics,pPen, COSD(x)*212+100, SIND(x)*220-133, COSD(x)*212+100, 92)
next x
'main - bottom side
#g_dat.nAngleStart=250
#g_dat.nAngleEnd=290
for x= int(#g_dat.nAngleStart) to int(#g_dat.nAngleEnd) step  ticspace
GdipDrawLine(pGraphics,pPen,COSD(x)*212+100, SIND(x)*220+333, COSD(x)*212+100,108)
next x
...


Our complete section for drawing tic marks appears as follows:

...
int x
select #g_dat.sStyle
case ROUND2PENV
'main - left side
#g_dat.nAngleStart=20
#g_dat.nAngleEnd=-20
for x= int(#g_dat.nAngleStart) to int(#g_dat.nAngleEnd) step  -ticspace
GdipDrawLine(pGraphics,pPen, COSD(x)*220-133, SIND(x)*212+100, 92, SIND(x)*212+100)
next x
'main - right side
#g_dat.nAngleStart=160
#g_dat.nAngleEnd=200
for x= int(#g_dat.nAngleStart) to int(#g_dat.nAngleEnd) step  ticspace
GdipDrawLine(pGraphics,pPen, COSD(x)*220+333, SIND(x)*212+100, 108, SIND(x)*212+100)
next x
case ROUND2PENH
'main - top side
#g_dat.nAngleStart=-250
#g_dat.nAngleEnd=-290
for x= int(#g_dat.nAngleStart) to int(#g_dat.nAngleEnd) step  -ticspace
GdipDrawLine(pGraphics,pPen, COSD(x)*212+100, SIND(x)*220-133, COSD(x)*212+100, 92)
next x
'main - bottom side
#g_dat.nAngleStart=250
#g_dat.nAngleEnd=290
for x= int(#g_dat.nAngleStart) to int(#g_dat.nAngleEnd) step  ticspace
GdipDrawLine(pGraphics,pPen,COSD(x)*212+100, SIND(x)*220+333, COSD(x)*212+100,108)
next x
case ROUNDCLOCK12
'main
for x= int(#g_dat.nAngleStart) to int(#g_dat.nAngleEnd) step  ticspace
GdipDrawLine(pGraphics,pPen,COSD(x)*86 +100, SIND(x)*86+100,COSD(x)*73+100, SIND(x)*73+100)
next x
'minor
for x= int(#g_dat.nAngleStart)+ tichalfspace to int(#g_dat.nAngleEnd) step  tichalfspace
GdipDrawLine(pGraphics,pPen, COSD(x)*86 +100, SIND(x)*86+100, COSD(x)*78+100, SIND(x)*78+100)
next x
default
'main
for x= int(#g_dat.nAngleStart) to int(#g_dat.nAngleEnd) step  ticspace
GdipDrawLine(pGraphics,pPen, COSD(x)*86 +100, SIND(x)*86+100, COSD(x)*73+100, SIND(x)*73+100)
next x
'minor
for x= int(#g_dat.nAngleStart)+ tichalfspace to int(#g_dat.nAngleEnd) step  ticspace
GdipDrawLine(pGraphics,pPen,COSD(x)*86 +100, SIND(x)*86+100,COSD(x)*78+100, SIND(x)*78+100)
next x
endselect
...


______________________

Coming Next - Drawing the Background - Drawing Scale Numbers

LarryMc
Larry McCaughn :)
Author of IWB+, Custom Button Designer library, Custom Chart Designer library, Snippet Manager, IWGrid control library, LM_Image control library