CPUG HOME QMAKE RCS AMMA HOME GAMA HOME

AMMA PROGRAMMING NOTES
Centre for Vision, Speech & Signal Processing


  CONTENTS
  FEEDBACK
AMMA Programming Notes

  AMMA CONCEPTS
This page brings to your attention some important issues that will tend to catch you out!

When using AMMA for the first time, you'll find there's a few surprises, such as when dealing with BIG and SMALL objects. This page will give details on:

  The distinction between Big and Small objects
  Coordinate systems in AMMA: the order of indices and vector components
  Copying nested templated big objects
  IndexC versus int?


The Distinction Between Big and Small Objects

The main difference is in the way the assignment operator and copy constructor work. Small objects behave like basic 'C++' types, in which a new instance of the object is created with every new variable and assignment make a copy of the entire object. Big objects behave more like pointers: assignment only copies the pointer to the body of the class. This allows you to have more than one handle to a class. The object itself is stored in the heap. All the problems of allocating and deallocating space on the heap are invisibly handled for you.

This may seem a bit confusing so here's an example:

 int x,y;   // Create two variables.
 x = 2;     // Assign the value 2 to x.
 y = x;     // Copy x to y.
 y++;       // Increment y.

As you would expect this code fragment leaves with x == 2 and y == 3. Now let's use an integer array from AMMA:

 Array1d<int> x(1),y(1); // Create a one element array.
 x[0] = 2;            // Assign value 2 to first element.
 y = x;               // x and y are now handles to the same object.
 y[0]++;              // This is now the same as x[0]++

This code leaves x[0] == 3 and y[0] == 3. If you wish assignment to make an actual copy of the object you must do so explicitly:

 Array1dC<int> x(1),y(1); // Create a one element array.
 x[0] = 2;             // Assign value 2 to first element.
 y = x.Copy();         // y is now a copy of x.
 y[0]++;      

This behaves as the first example leaving with x == 2 and y == 3. Using the copy constructor with big objects behaves in exactly the same was as the assignment operator.

 Array1dC<int> x(1); // Create a one element array.
 Array1dC<int> y(x); // Create y with copy constructor.
 x[0] = 2;           // Assign value 2 to first element of x.
 y[0]++;             // x[0] is now equal to 3.

A typical example of big objects are VectorC, MatrixC, DListC and ImageC. Some small objects are Vector2dC and Matrix2d2C.

If you are wondering when you should use a big object when writing a class yourself, here are some notes from Charles.


Copying nested templated big objects

What happens if I use the Copy() function to copy for example an array of images? - like this:
Array1dC<ImageC<RealT> > a1(6), a2;
.... // initialise the images in a1
.... 
a2 = a1.Copy();
....
What exactly gets copied here? In fact only the array gets copied, not the images themselves; i.e. you get a new array in a2 which contains pointers to the original images in a1. If you want a "deep" copy, so that all of the images in the array get copied into new images, you have to do it explicitly:
a2 = a1.Copy();
for (IndexC i=a1.IMin(); i<=a1.IMax(); ++i)  a2[i] = a1[i].Copy();
(If you have a large array, you can do the iteration more efficiently using an array iterator, in this case Array1dIter2C.)

2D coordinate systems in AMMA

In 2D AMMA objects, such as arrays, matrices and images, the indices are in the order: row, column (as in conventional matrix notation). In pairs of reals (e.g. 2D vectors and points), the components are in the order x, y. Normally these two categories of objects do not interact. However, when they do (e.g. if we want to construct a pixel position from a 2D vector in PixelC::PixelC(const Point2dC & pt), the AMMA convention is this:

  • The row index is associated with the x value
  • The column index is associated with the y value

The implication is that AMMA adopts a 2D coordinate system in which the x coordinate points downwards, and the y coordinate to the right. Not what you were expecting? It has the advantages that:

  • the coordinate system is anti-clockwise, as is conventional in mathematics
  • the first array coordinate is associated with the first vector component etc.

Do I Use IndexC or int?

The problems with the basic int type in C / C++ are manifold. Our main complaints are:

  • When an int is combined with an unsigned int, the int is converted to unsigned int before the operation is performed. This can lead to bizarre results for multiplication, division and modulo operators where one of the operands is negative.
  • The int division operator always rounds towards zero, as does conversion from float or double, regardless of the sign of the operands.
  • The size of many AMMA objects is returned as unsigned, which typically causes compilation warnings to be generated by comparison operations in loops etc. unless IndexC is used.

We have attempted to address all of these problems in the IndexC class (also typedefed as IndexT). So, for anything that could be regarded as an index variable (for loop variables, array indices etc.) we would recommend using IndexC.

Charles Galambos, Bill Christmas & Simon Cunnington;   Last modified: Tue May 30 14:49:21 BST 2000