2015-09-26

Basics - Part 3: Tidying up numeric output

In Part 2 last week I explained how to display numeric output when you have no mechanism to actually "print to the screen". Hopefully you've got a modified attitude indicator that has the speed and altitude displayed in the simplest of forms: a numeric readout. Click here to see what you should have so far.

Dual Digit
Number Strip
The problem as discussed so far is where you have a number that changes too rapidly; you may, for example, be holding an altitude of 15000 feet very well, but your indicated altitude will be fluctuating up and down by a few feet which means the final digits of your readout could be fluctuating so much as to be unreadable or inaccurate.

In such circumstances it's better to make your number strip twice as wide, listing numbers in tens, so that at any time the pilot can see which direction the numbers are moving and be able to maintain height properly. You can see such a strip here to the right.

You will, of course, need to make a mask to cover the double-digit size, and adjust your XML accordingly, but you can then remove the "%" operator from the expression and have a smooth-scrolling number.
Dual Digit
Mask

When you're making the mask, remember that for this kind of  "rolling readout" you'll need a bit of extra space at the top and bottom so that when between one or another of the number marks the pilot can still easily tell which two marks it's between.

So we can change our final two elements by replacing them with this single-element dual-digit display - here's the complete xml for our modified gauge, assuming we've named the two new images "HSIb_dual_figure_scale.bmp" and "HSIb_dual_character_mask.bmp":

<?xml version="1.0" encoding="utf-8"?>
<Gauge Name="Attitude Indicator" Version="2.0">
  <Image Name="Attitude_Background2.bmp" ImageSizes="320,240,320,240"/>
  <Element>
    <Position X="160"  Y="120"/>
    <Image Name="Attitude_Card.bmp" ImageSizes="240,240,240,240">
      <Axis X="120" Y="120"/>
    </Image>
    <Rotate>
      <Value>(A:sim/cockpit2/gauges/indicators/roll_AHARS_deg_pilot, ndegree)</Value>
    </Rotate>
  </Element>
  <Element>
    <Position X="160"  Y="120"/>
    <Image Name="Attitude_Inner.bmp" ImageSizes="240,240,240,240">
      <Axis X="120" Y="120"/>
    </Image>
    <Shift>
      <Value Minimum="-25" Maximum="25">(A:sim/cockpit2/gauges/indicators/pitch_AHARS_deg_pilot, negative)</Value>
      <Scale Y="0.85"/>
    </Shift>
    <Rotate>
      <Value>(A:sim/cockpit2/gauges/indicators/roll_AHARS_deg_pilot, ndegree)</Value>
    </Rotate>
  </Element>
  <Element>
    <Position X="160"  Y="120"/>
    <Image Name="Attitude_Outer.bmp" ImageSizes="240,240,240,240">
      <Axis X="120" Y="120"/>
    </Image>
    <Rotate>
      <Value>(A:sim/cockpit2/gauges/indicators/roll_AHARS_deg_pilot, ndegree)</Value>
    </Rotate>
  </Element>
  <Element>
    <Position X="5" Y="5"/>
    <MaskImage Name="HSIb_character_mask.bmp" ImageSizes="12,14,12,14">
      <Axis X="0" Y="0"/>
    </MaskImage>
    <Image Name="HSIb_figure_scale.bmp" ImageSizes="12,168,12,168">
      <Nonlinearity>
        <Item Value="0" X="0" Y="140"/>
        <Item Value="9" X="0" Y="14"/>
      </Nonlinearity>
    </Image>
    <Shift>
      <Value>(A:sim/cockpit2/gauges/indicators/airspeed_kts_pilot) 100 div</Value>
    </Shift>
  </Element>
  <Element>
    <Position X="17" Y="5"/>
    <MaskImage Name="HSIb_character_mask.bmp" ImageSizes="12,14,12,14">
      <Axis X="0" Y="0"/>
    </MaskImage>
    <Image Name="HSIb_figure_scale.bmp" ImageSizes="12,168,12,168">
      <Nonlinearity>
        <Item Value="0" X="0" Y="140"/>
        <Item Value="9" X="0" Y="14"/>
      </Nonlinearity>
    </Image>
    <Shift>
      <Value>(A:sim/cockpit2/gauges/indicators/airspeed_kts_pilot) (A:sim/cockpit2/gauges/indicators/airspeed_kts_pilot) 100 div 100 * - 10 div</Value>
    </Shift>
  </Element>
  <Element>
    <Position X="29" Y="5"/>
    <MaskImage Name="HSIb_character_mask.bmp" ImageSizes="12,14,12,14">
      <Axis X="0" Y="0"/>
    </MaskImage>
    <Image Name="HSIb_figure_scale.bmp" ImageSizes="12,168,12,168">
      <Nonlinearity>
        <Item Value="0" X="0" Y="140"/>
        <Item Value="9" X="0" Y="14"/>
      </Nonlinearity>
    </Image>
    <Shift>
      <Value>(A:sim/cockpit2/gauges/indicators/airspeed_kts_pilot) (A:sim/cockpit2/gauges/indicators/airspeed_kts_pilot) 10 div 10 * - %</Value>
    </Shift>
  </Element>
  <Element>
    <Position X="255" Y="5"/>
    <MaskImage Name="HSIb_character_mask.bmp" ImageSizes="12,14,12,14">
      <Axis X="0" Y="0"/>
    </MaskImage>
    <Image Name="HSIb_figure_scale.bmp" ImageSizes="12,168,12,168">
      <Nonlinearity>
        <Item Value="0" X="0" Y="140"/>
        <Item Value="9" X="0" Y="14"/>
      </Nonlinearity>
    </Image>
    <Shift>
      <Value>(A:sim/cockpit2/gauges/indicators/altitude_ft_pilot) 10000 div</Value>
    </Shift>
  </Element>
  <Element>
    <Position X="267" Y="5"/>
    <MaskImage Name="HSIb_character_mask.bmp" ImageSizes="12,14,12,14">
      <Axis X="0" Y="0"/>
    </MaskImage>
    <Image Name="HSIb_figure_scale.bmp" ImageSizes="12,168,12,168">
      <Nonlinearity>
        <Item Value="0" X="0" Y="140"/>
        <Item Value="9" X="0" Y="14"/>
      </Nonlinearity>
    </Image>
    <Shift>
      <Value>(A:sim/cockpit2/gauges/indicators/altitude_ft_pilot) (A:sim/cockpit2/gauges/indicators/altitude_ft_pilot) 10000 div 10000 * - 1000 div</Value>
    </Shift>
  </Element>
  <Element>
    <Position X="279" Y="5"/>
    <MaskImage Name="HSIb_character_mask.bmp" ImageSizes="12,14,12,14">
      <Axis X="0" Y="0"/>
    </MaskImage>
    <Image Name="HSIb_figure_scale.bmp" ImageSizes="12,168,12,168">
      <Nonlinearity>
        <Item Value="0" X="0" Y="140"/>
        <Item Value="9" X="0" Y="14"/>
      </Nonlinearity>
    </Image>
    <Shift>
      <Value>(A:sim/cockpit2/gauges/indicators/altitude_ft_pilot) (A:sim/cockpit2/gauges/indicators/altitude_ft_pilot) 1000 div 1000 * - 100 div</Value>
    </Shift>
  </Element>
  <Element>
    <Position X="291" Y="5"/>
    <MaskImage Name="HSIb_dual_character_mask.bmp" ImageSizes="24,14,24,14">
      <Axis X="0" Y="0"/>
    </MaskImage>
    <Image Name="HSIb_dual_figure_scale.bmp" ImageSizes="24,168,24,168">
      <Nonlinearity>
        <Item Value="0" X="0" Y="140"/>
        <Item Value="90" X="0" Y="14"/>
      </Nonlinearity>
    </Image>
    <Shift>
      <Value>(A:sim/cockpit2/gauges/indicators/altitude_ft_pilot) (A:sim/cockpit2/gauges/indicators/altitude_ft_pilot) 100 div 100 * -</Value>
    </Shift>
  </Element>
  <Element>
    <Position X="40"  Y="0"/>
    <Image Name="Attitude_Overlay.bmp" ImageSizes="240,240,240,240"/>
  </Element>
</Gauge>


You'll notice that I have modified the ImageSizes attributes, the Nonlinearity and the expression - the expression is probably the hardest bit to understand, so for clarity we'll break down exactly how this works:


  • Get the altitude and push to the stack
  • Get the altitude and push to the stack again
  • Push "100" to the stack
  • Integer division (altitude/100 as an integer) and push result back to the stack
  • Push "100" to the stack
  • Multiply (result of previous integer division * 100) and push result back to stack
  • Subtract (altitude - result from the above multiplication )
Notice that we do not end with an integer division, and nor do we use the modulo operator (%) to round the number. Because we now have our nonlinearity between 0 and 90 rather than 0 and 99, the result is a smooth-scrolling double digit at the end.

I'll be honest - I'm thoroughly bored of describing this now! I'm really hoping that these last 3 lessons have given you a good handle on how to produce numeric displays; Please do give me comments and suggestions - if you're stuck feel free to ask and I will try and help you out!

Next up will be my custom Attitude Indicator (created from scratch rather than modifying the default Saitek one), a gauge that I hope will be the perfect complement to my HSI. I'll see you all then!


2 comments:

  1. Nice and instructional blog. I'm wondering if you ever finished your custom Attitude indicator.

    ReplyDelete
  2. Thank you! Unfortunately my life took a turn (and my computer died) so I had to put this, and my other project "Pivionics", on hold - I would love to return to it one day, but my circumstances right now do not allow for it.

    I do hope the information here is of some help anyway, and if I manage to get back to the projects I will be sure to post again. Thanks again for your interest!

    ReplyDelete

Please feel free to leave comments, add questions, correct my errors, leave handy hints, suggest additions, request new gauges and so forth - No abuse please, and no flaming each other!