Mapping
Know where you are.
Site Map Feedback

Download:

Up Bitmap Colour Interpolation Mapping OpenGL Vector
Global.h is the top of the graphics heirarchy and provides methods for the Mapping of Normalized Parametric Intervals as well as assembly language speed-ups for functions casting to double (Floor, Round, Truncate, Frac), as well as (Mod, sincos, sinc).
Mapping

Mapping a value from one scale to another is one of the principle operations that is done constantly in computer graphics. Knowing which units you are currently working on (inches, millimetres, elephants) is crucial when working out anything. Keep that as an issue for the levels close to the user interface and have all floating point values vary like a percentage. Instead of using the [0%,100%] percentage range, though, there are advantages to using a "per-unit" range [0,1] which allows easy conversion (mapping/scaling) by multiplying. The usual name for these per-units is Signed or Unsigned Normalised Intervals. That means that Signed things will have values in the range [-1,1] and Unsigned in [0,1]. What is a sensible, simple standard name for those? Folk seem to call them 'parameters' (far too ambiguous) and use s,t,u and v as variable names implying a unit range. Whether you should use Signed or Unsigned depends on whether your value has a null mid-point (use Unsigned) or whether you will be adding or multiplying a lot of values. If adding lots of random values, Signed Intervals will tend to say around zero. For mixing greyscale levels or colour components (if each component Red,Green,Blue is in the range [0,1]), many Unsigned Normalised Intervals can be multiplied together and the result is always another Unsigned Normalised Interval (the product can only get smaller or, if one of the number is 1, stay the same).

Normalizing a Vector means making its length one unit without changing its direction. Normalized parameters vary up to a unit length (in both directions for the signed ones) from zero. Since Vectors describe a journey, a Normalized parameter can be considered to be the distance travelled along a unit vector. The following image shows a couple of parallel scales drawn as numbered lines and positioned so that their middles line up.
Interval
This means that their end points can be joined with green lines to a focus point. A Normalised Interval will be another parallel line with a length of one, positioned so that its ends touch the green lines too. Now pick any point on the big scale and draw a line to the focus point (one of the blue lines) and the normalised value will be where the blue line crosses the Normalised Interval line. Once you have a Normalised value, you can play with it without worrying about the scale. As a result, there are many 'black boxes' in gFilters, for example, which take and return Normalised Intervals. gColor uses them a lot for smoothing colour-changes and converting from different colour systems (RGB-HSL-HSV).

Now that all scales can be reduced to Signed or Unsigned Normalized Intervals, all that's left to see the methods used to map is from one to the other! Global.h has a couple of templates for mapping from signed to unsigned and back:

  // Minimise mapping by having everything return normalised ranges [0,1] or [-1,1].
  // Unsigned Interval is [0,1]; Signed interval is [-1,1]; These change between the two (useful for double or float):
  template<typename T> T  Unsigned(T t) {return (t+1)/2;} // From Signed
  template<typename T> T    Signed(T t) {return 2*t-1;}   // From Unsigned

Hopefully you can visualise a range of numbers between -1 and 1 being shifted by the (t+1) of the first template to [0,2] and then compressed by the /2 to the range [0,1] and similarly going back the other way, the [0,1] range getting stretched by the 2*t of the second template and shifted left one unit by the -1 to alter the range to numbers between -1 and 1.

Having defined that floating point operations will work on intervals, a way to get from the interval to the original scale and back is needed. This is done using another pair of simple templates in Global.h:

  template<typename T> double Parameterize(T x, T a, T b) {ASSERT(a!=b); return double(x-a)/(b-a);} // x is normally between a and b. returns 0 if x==a, 1 if x==b, 0.5 if x is in the middle of a and b etc.
  template<typename T>  T Interpolate(double t, T a, T b) {return T(a+(b-a)*t);} // The reverse of Parameterize: if t=0.5, returns the value in the middle of a and b.
Thermometer

These functions both work on unsigned parameters [0,1]. To see how they work, imagine the temperature scales, Centigrade and Fahrenheit. Centigrade goes from 0 when water freezes, to 100 when water boils. Fahrenheit is proportional to the centigrade scale but is 32 when water freezes and 212 when it boils. Since Centigrade is trivial to map to (just multiply the parameter by 100) going between the two scales can be demonstrate easily, rather than between one and a parameter.

If room temperature is about 25 Centigrade, that is 0.25 up the scale. To find that in Fahrenheit would need Interpolate(0.25, 32, 212); which would calculate: (32+(212-32)*0.25 giving 77 Fahrenheit. This particular example can extend beyond the provided limits, so the parameter, t, can have any value and will return a Fahrenheit scale value (the accuracy may decline if the minimum and maximum are close together and the parameter is huge).

If you wanted to find out how far up the scale 50 Fahrenheit was, just use Parameterize(50, 32.0, 212.0); which would calculate: (50-32)/(212-32.0) which is 18/180.0 giving 0.1 or 10 Centigrade.

To map a number from one scale to another could be done like this: NewValue=Interpolate(Parameterize(OldValue, OldMinimum,OldMaximum), NewMinimum,NewMaximum); Which may look complex but can be made easier to understand if you think of using a graph:

Linear Interpolation

The axes on this temperature graph are deliberately drawn with different scales (which won't matter for this linear case). The gradient (slope) of the blue line defines how X values (along the bottom axis) map to Y values (along the vertical axis). The red lines could indicate minimum and maximum values and the green line, some value of X which shoots up from the X-axis, hits the blue line and then travels to the Y-axis to give the new Y value.

Now you know how the Interpolate function allows you to change from a parameter to a value from a scale, but not why it is called 'Interpolate'. Interpolating is calculating an unknown value between two known values. If you imagine that the places where the red lines hit the blue line are two points, the blue line is drawn between the points and finding where points exist on the line using X values. Because the blue line is straight (linear) this process is called "Linear Interpolation". Things get more interesting when the blue line is curved, but the principle remains the same: a function is called with a parameter,minimum and maximum and returns a value. Find out more in the Interpolation section.

Quantized Serialization (saving doubles as integers)

Human Mesh

Another use of mapping is the lossy compression (quantization) of data when saving to files. Imagine a three dimensional model of a human, made up of millions of triangles and/or quads (common in the marble statue industry and computer games); each triangle needs its points to be saved - but how accurately? Saving absolute float or double-precision coordinates for each vertex is obvious, but it is also possible to think in terms of mapped ranges for each axis. For example, 0 could be the front-most part (toe-nails) and 1 could be the furthest back part (shoulders or bottom). For a low resolution model, you could use a range of [0,255] and save BYTE positions with a huge saving in file size! For a higher resolution model, you could use a range of [0,UINT_MAX] and save unsigned int positions. If the most detailed parts of the model (hands and face in the human) are all near the top of the model, for example, a non-linear mapping could be interpolated so that most of the detail is at the top of the model. To reconstruct the model, the mapping style, range, scale, origin and orientation would need to be saved as well as the vertex list and triangle/quad indexes into the vertex list.

This page has covered mapping one dimension to another. Mapping is also used extensively to move, for example, three dimensional world coordinate systems to two dimensional screen systems. This is done using matrices and can be very time-consuming to program (because you can put mad numbers into the matrices and get results that look OK... for a while). Fortunately, there are simple ways to go about understanding matrix transformations. On this site, that journey starts with gPlane.

 (173) Last modified: Tue, 15 Dec 2009 13:53:47 +0000

You can email, bookmark, or share this page by clicking the social networking icons below:

  • E-mail this page to a friend!
  • Google
  • Live
  • YahooMyWeb
  • TwitThis
  • StumbleUpon
  • Digg
  • Reddit
  • Facebook
  • del.icio.us
  • LinkedIn
  • Mixx
  • connotea
  • Sphinn
  • Slashdot
  • Technorati