BBC BASIC for Windows
Programming >> Communication and Input/Output >> Meters-displays
http://bb4w.conforums.com/index.cgi?board=communication&action=display&num=1339969801

Meters-displays
Post by dynamic35 on Jun 17th, 2012, 9:50pm

One likes to write and image program where there is a vehicle velocity display: speed on the outer circle with arrow pointing the speed value and distance as a number sittings at the center of the circle.
There are the excellent Richardian wall clock example where one can see how pointers/ arrows move in circle (hours, minutes, seconds)
Is there some other similar ones done for physical measurement values like wind speed , wind direction etc?

Thank you
Dynamic35



Re: Meters-displays
Post by DDRM on Jun 18th, 2012, 09:37am

Hi Dynamic35,

You have various options, each with strengths and weaknesses. Richard's clock programme uses images for the face and hands, which is probably easiest if you want a "realistic" look, but involves some reasonably fancy code (using Windows API commands) to plot the rotated scaled images. If you want to follow this approach it should be reasonably straightforward to modify the clock programme.

An alternative is to draw everything yourself within the program. The complexity of this depends on how flexible you want your code to be (do you need to be able to draw the dial in different sizes or positions, or with different speed ranges, for example?).

Here's a simple attempt to provide an outline solution, which provides some flexibility in terms of size and position.
Code:
      MODE 21
      px%=600
      py%=350
      radius%=300
      PROCdrawspeedo(px%,py%,radius%)
      FOR x%=0 TO 1000
        PROCupdatespeedo(px%,py%,radius%,120*ABS(SIN(x%/200)),1000+x%)
        WAIT 2
      NEXT x%
      
      END
      :
      DEFPROCdrawspeedo(cx%,cy%,r%)
      LOCAL x%,px%,py%,a,s$
      *FONT System Fixed Font,8
      GCOL 0
      CIRCLE FILL cx%,cy%,r%
      GCOL 15
      CIRCLE cx%,cy%,r%
      VDU 5
      FOR x%=0 TO 200 STEP 10
        s$=STR$(x%)
        a=RAD(250-x%*1.5)
        px%=cx%+r%*0.95*COS(a)
        py%=cy%+(r%*0.95-2*@vdu%!220)*SIN(a)+@vdu%!220
        IF px%>cx% THEN px%-=COS(a)*LEN(s$)*2*@vdu%!216
        MOVE px%,py%
        IF py%
        PRINT s$
      NEXT x%
      VDU 4
      ENDPROC
      :
      DEFPROCupdatespeedo(cx%,cy%,r%,s%,d%)
      LOCAL s$
      s$=STR$(d%)
      a=RAD(250-s%*1.5)
      *REFRESH OFF
      GCOL 0
      CIRCLE FILL cx%,cy%,r%*0.75
      GCOL 1
      LINE cx%+r%*0.4*COS(a),cy%+r%*0.4*SIN(a),cx%+r%*0.7*COS(a),cy%+r%*0.7*SIN(a)
      VDU 5
      MOVE cx%-LEN(s$)*@vdu%!216,cy%+@vdu%!220
      GCOL 15
      PRINT s$
      *REFRESH ON
      VDU 4
      ENDPROC

 


A nice enhancement would be to use private variables to hold the position of the pointer so you can use EOR printing to rub out the old position before drawing it in its new position during updating, rather than my slightly crude "draw a black circle" approach. This version also doesn't scale very gracefully - the positioning of the numbers isn't quite right, and you would need to scale the font if you made it substantially bigger or smaller.

Hope that is helpful!

D
Re: Meters-displays
Post by admin on Jun 18th, 2012, 11:59am

on Jun 18th, 2012, 09:37am, DDRM wrote:
Here's a simple attempt to provide an outline solution, which provides some flexibility in terms of size and position.

A couple of comments on your code, if I may. Firstly this command:

Code:
      *FONT System Fixed Font,8 

There's no font on my PC called System Fixed Font so Windows falls back to choosing a default font. You might just as well have written:

Code:
      *FONT Garbage,8 

for all the difference it would have made! If you are really trying to select the 'System Fixed Font' its name is FixedSys, but since it's a fixed point size (9pt in the case of a 96 DPI system) you would need to select it as:

Code:
      *FONT FixedSys,9 

but that might well not work correctly at a DPI value other than 96. In any case you could achieve the same effect simply by selecting MODE 20 rather than MODE 21!

I'm somewhat mystified as to the function of this line:

Code:
        IF py% 

Is it a residue of some code you have deleted, or is it actually supposed to do something?

Quote:
A nice enhancement would be to use private variables to hold the position of the pointer so you can use EOR printing to rub out the old position

Indeed that would be more efficient, and it would allow you to use a longer pointer without accidentally erasing the numbers.

A version with these and a few other changes made is as follows:

Code:
      MODE 8
      ORIGIN 640,512
      COLOUR 128+4
      CLS
      OFF
      px% = 0
      py% = 0
      radius% = 300
      PROCdrawspeedo(px%,py%,radius%)
      FOR x% = 0 TO 1256
        PROCupdatespeedo(px%,py%,radius%,200*ABS(SIN(x%/200)),x%)
        WAIT 2
      NEXT x%
      
      END
      ;
      DEFPROCdrawspeedo(cx%,cy%,r%)
      LOCAL x%,px%,py%,a,s$
      GCOL 0
      CIRCLE FILL cx%,cy%,r%
      GCOL 15
      CIRCLE cx%,cy%,r%
      VDU 5
      FOR x% = 0 TO 200 STEP 10
        s$ = STR$(x%)
        a = RAD(250-x%*1.5)
        px% = cx%+r%*0.9*COS(a)
        py% = cy%+r%*0.9*SIN(a)
        MOVE px%-LEN(s$)*@vdu%!216,py%+@vdu%!220
        PRINT s$;
      NEXT x%
      VDU 4
      ENDPROC
      ;
      DEFPROCupdatespeedo(cx%,cy%,r%,s%,d%)
      LOCAL s$
      PRIVATE erase%, olds%
      s$ = STR$(d%)
      GCOL 3,1
      VDU 23,23,2;0;0;0;
      IF erase% THEN
        a = RAD(250-olds%*1.5)
        LINE cx%+r%*0.2*COS(a),cy%+r%*0.2*SIN(a),cx%+r%*0.8*COS(a),cy%+r%*0.8*SIN(a)
      ENDIF
      a = RAD(250-s%*1.5)
      LINE cx%+r%*0.2*COS(a),cy%+r%*0.2*SIN(a),cx%+r%*0.8*COS(a),cy%+r%*0.8*SIN(a)
      GCOL 0
      RECTANGLE FILL cx%-8*@vdu%!216,cy%-@vdu%!220,16*@vdu%!216,2*@vdu%!220
      GCOL 15
      MOVE cx%-LEN(s$)*@vdu%!216,cy%+@vdu%!220
      VDU 5
      PRINT s$;
      VDU 4
      olds% = s%
      erase% = TRUE
      ENDPROC 

Richard.
Re: Meters-displays
Post by DDRM on Jun 18th, 2012, 1:30pm

Hi Richard,

Thanks for the improvements. Your way of positioning the numbers is (of course) much neater than mine...

I didn't use ORIGIN (and went for the additional complication of an offset in the routine) on the assumption the OP would want to draw one or more dials on a display where other graphics would also be plotted.

*FONT: I tried this, and it changed the font size, so I assumed it must be working - I admit I didn't try it out rigorously.

Originally, I just tried Code:
* FONT 8 
in the hope that I could change the size without specifying the font (partly so it wouldn't mess up the font allocated elsewhere - though I guess if it was specified as anything facy my dial would have been in trouble...).

Ideally, I wanted to be able to scale the font according the dial radius (presumably one would need OSCLI for this, to allow a variable font size). Will @vdu%!216 and 220 work accurately if you change the font? I vaguely recall a conversation on Yahoo to the effect that they won't. That's why I wanted to use the system font, in the hope that would help.

IF py%: Yes, a sloppy hangover I missed when tidying!

Best wishes,

D
Re: Meters-displays
Post by admin on Jun 18th, 2012, 6:04pm

on Jun 18th, 2012, 1:30pm, DDRM wrote:
I didn't use ORIGIN (and went for the additional complication of an offset in the routine)

I have not removed any of the 'offset' code, as you seem to be implying. I simply moved the ORIGIN to the centre because that is often useful in graphics applications.

Quote:
on the assumption the OP would want to draw one or more dials on a display where other graphics would also be plotted.

That is still perfectly possible. The ORIGIN is not replacing the positioning capabilities of your original code.

Quote:
*FONT: I tried this, and it changed the font size, so I assumed it must be working - I admit I didn't try it out rigorously.

It is undesirable to rely on the Windows font 'fallback', because there is no guarantee that two different PCs will make the same choice. In the unlikely circumstance that you specifically want that behaviour I would suggest using a font name that makes it obvious what you are doing, for example:

Code:
      *FONT NonExistentFont,8 

Quote:
Will @vdu%!216 and 220 work accurately if you change the font? I vaguely recall a conversation on Yahoo to the effect that they won't.

I'm not sure what you mean by "accurately". They should certainly correspond reliably to the values returned for tmAveCharWidth and tmHeight, since that is how they are set! But of course the average character width is often not very useful if you have selected a proportional-spaced font!

Richard.
Re: Meters-displays
Post by DDRM on Jun 19th, 2012, 08:28am

Hi Richard,

I didn't mean to imply that you had involved the offset capabilities - I thought it was obvious that they were still there. I was just commenting that I didn't use ORIGIN instead so that I didn't affect the outside frame of reference (too much - of course playing with the font and colours does to some extent).

Agreed, my use of *FONT was unsatisfactory. Again, I was trying to avoid affecting the environment too much by changing the font, and fell between two stools. Looking through HELP now, I see you provide a function to find out what it is, so I could do this on entry, and then restore it on exit... though I note that won't give the size to set.

@vdu%216 and 220: I had thought this was a fixed characteristic of the MODE when it was defined, and that changing the font would mean the letters painted wouldn't match the spec, but I see from trying now that they are altered - that's really useful - if, as you say, you use a non-proportional font...

Best wishes,

D
Re: Meters-displays
Post by admin on Jun 20th, 2012, 08:11am

on Jun 19th, 2012, 08:28am, DDRM wrote:
I was just commenting that I didn't use ORIGIN instead so that I didn't affect the outside frame of reference

Well, if you look you'll see that my only use of ORIGIN is in the 'main program' (which represent's the end-user's code), so if anything it demonstrates that the 'meter' procedures aren't affected by, and don't affect, the "outside frame of reference" in that respect.

Quote:
(too much - of course playing with the font and colours does to some extent).

Indeed. You could consider borrowing the code in the MULTIWIN.BBC library, which saves-and-retores the current VDU state fairly 'completely'.

Richard.
Re: Meters-displays
Post by JGHarston on Jul 18th, 2012, 1:38pm

on Jun 19th, 2012, 08:28am, DDRM wrote:
Agreed, my use of *FONT was unsatisfactory.

You could use the following subroutine which will attempt to select a font, and the tell you if it was successful so that you can make another attempt if it wasn't:
Code:
      REM Font_Select - Attempt to select a font, returns non-zero if failed
      REM ------------------------------------------------------------------
      REM Returns FALSE if font not selected
      :
      DEFFNFont_Select(font$)
      LOCAL face%,face$:DIM face% LOCAL 31
      SYS "CharUpperBuff", !^font$, LEN font$
      OSCLI"FONT "+font$
      SYS "GetTextFace", @memhdc%, 32, face%:face$=$$face%
      SYS "CharUpperBuff", !^face$, LEN face$
      font$=LEFT$(font$,INSTR(font$+",",",")-1)
      =font$=face$
      : 

Then you can do things like:
IF FNFont_Select("Transport")=0 THEN A%=FNFont_Select("Ariel")

If the specified font is the null string "" then the WINBBC font is selected. This is always available to BBC BASIC for Windows programs and so can always be used as a fall-back font, for example:
IF FNFont_Select("Courier")=0 THEN A%=FNFont_Select("")

Re: Meters-displays
Post by admin on Jul 21st, 2012, 9:59pm

on Jul 18th, 2012, 1:38pm, JGHarston wrote:
IF FNFont_Select("Transport")=0 THEN A%=FNFont_Select("Ariel")

Ariel is a character in Shakespeare's The Tempest, a moon of Uranus, and the name of the BBC's in-house staff magazine. As far as I know there isn't a font of that name (although there is a font called Arial).

Richard.
Re: Meters-displays
Post by RayRayTea on Aug 6th, 2012, 1:07pm

on Jun 18th, 2012, 11:59am, Richard Russell wrote:
A couple of comments on your code, if I may.



A version with these and a few other changes made is as follows:

Code:
      MODE 8
      ORIGIN 640,512
      COLOUR 128+4
      CLS
      OFF
      px% = 0
      py% = 0
      radius% = 300
      PROCdrawspeedo(px%,py%,radius%)
      FOR x% = 0 TO 1256
        PROCupdatespeedo(px%,py%,radius%,200*ABS(SIN(x%/200)),x%)
        WAIT 2
      NEXT x%
      
      END
      ;
      DEFPROCdrawspeedo(cx%,cy%,r%)
      LOCAL x%,px%,py%,a,s$
      GCOL 0
      CIRCLE FILL cx%,cy%,r%
      GCOL 15
      CIRCLE cx%,cy%,r%
      VDU 5
      FOR x% = 0 TO 200 STEP 10
        s$ = STR$(x%)
        a = RAD(250-x%*1.5)
        px% = cx%+r%*0.9*COS(a)
        py% = cy%+r%*0.9*SIN(a)
        MOVE px%-LEN(s$)*@vdu%!216,py%+@vdu%!220
        PRINT s$;
      NEXT x%
      VDU 4
      ENDPROC
      ;
      DEFPROCupdatespeedo(cx%,cy%,r%,s%,d%)
      LOCAL s$
      PRIVATE erase%, olds%
      s$ = STR$(d%)
      GCOL 3,1
      VDU 23,23,2;0;0;0;
      IF erase% THEN
        a = RAD(250-olds%*1.5)
        LINE cx%+r%*0.2*COS(a),cy%+r%*0.2*SIN(a),cx%+r%*0.8*COS(a),cy%+r%*0.8*SIN(a)
      ENDIF
      a = RAD(250-s%*1.5)
      LINE cx%+r%*0.2*COS(a),cy%+r%*0.2*SIN(a),cx%+r%*0.8*COS(a),cy%+r%*0.8*SIN(a)
      GCOL 0
      RECTANGLE FILL cx%-8*@vdu%!216,cy%-@vdu%!220,16*@vdu%!216,2*@vdu%!220
      GCOL 15
      MOVE cx%-LEN(s$)*@vdu%!216,cy%+@vdu%!220
      VDU 5
      PRINT s$;
      VDU 4
      olds% = s%
      erase% = TRUE
      ENDPROC 


If I try to just copy, paste and run this code, the compiler automatically picks up all the instances of "radius" and attempts to interpret it as part of "rad" (makes sense)… so it produces a Syntax Error and I can't run it unless all instances of "radius" are changed to whatever non-keyword ("rdius" or"rds", for example).

So how come it works for you – I assume you tested it before posting, so it should have produced an error on your end too, or is there a setting in IDE that I'm missing :)
Re: Meters-displays
Post by admin on Aug 6th, 2012, 3:31pm

on Aug 6th, 2012, 1:07pm, RayRayTea wrote:
If I try to just copy, paste and run this code, the compiler automatically picks up all the instances of "radius" and attempts to interpret it as part of "rad"

It sounds as though you have the Lowercase Keywords option set. That is non-standard for BBC BASIC (all versions apart from BB4W force you to use capitals for keywords) and since most users don't set that option you will find many programs listed that are not compatible with it.

If you want to ensure that all programs you find listed on the web and elsewhere run, disable the Lowercase Keywords option. That is the default setting on installation and it will ensure maximum compatibility with other versions of BBC BASIC.

Richard.
Re: Meters-displays
Post by RayRayTea on Aug 7th, 2012, 03:08am

Right that was it – no idea how it ended up turned on though, must have been a mistake. Thanks!