bzindex(Array!multicomponent)
bzindex(multicomponent arrays)
Multicomponent arrays have elements which are vectors.  Examples
of such arrays are vector fields, colour images (which contain, say,
RGB tuples), and multispectral images.  Complex-valued arrays can
also be regarded as multicomponent arrays, since each element is
a 2-tuple of real values.

Here are some examples of multicomponent arrays:

bzindex(RGB24 example)

bzverb(\

  // A 3-dimensional array; each element is a length 3 vector of float
  Array<TinyVector<float,3>,3> A;  

  // A complex 2-dimensional array
  Array<complex<double>,2> B;

  // A 2-dimensional image containing RGB tuples
  struct RGB24 {
    unsigned char r, g, b;
  };

  Array<RGB24,2> C;
)

bzsubsect(Extracting components)

bzindex(extracting components)
bzindex(Array!extracting components)

Blitz++ provides some special support for such arrays.  The most
important is the ability to extract a single component.  For
example:

bzverb(
  Array<TinyVector<float,3>,2> A(128,128);
  Array<float,2> B = A.extractComponent(float(), 1, 3);
  B = 0;
)

The call to tt(extractComponent) returns an array of floats; this
array is a view of the second component of each element of A.
The arguments of tt(extractComponent) are: (1) the type of the
component (in this example, float); (2) the component number
to extract (numbered 0, 1, ... N-1); and (3) the number of 
components in the array.

This is a little bit messy, so Blitz++ provides a handy shortcut
using tt(operator[]):

bzverb(
  Array<TinyVector<float,3>,2> A(128,128);
  A[1] = 0;
)

The number inside the square brackets is the component number.
However, for this operation to work, Blitz++ has to already know
how many components there are, and what type they are.  It
knows this already for tt(TinyVector) and tt(complex<T>).
If you use your own type, though, you will have to tell
Blitz++ this information using the macro tt(BZ_DECLARE_MULTICOMPONENT_TYPE()).
This macro has three arguments:

bzindex(BZ_DECLARE_MULTICOMPONENT_TYPE)
bzverb(\
BZ_DECLARE_MULTICOMPONENT_TYPE(T_element, T_componentType, numComponents)
)
tt(T_element) is the element type of the array.  tt(T_componentType)
is the type of the components of that element.  tt(numComponents) is
the number of components in each element.

An example will clarify this.  Suppose we wanted to make a
colour image, stored in 24-bit HSV (hue-saturation-value) format.
We can make a class tt(HSV24) which represents a single pixel:

bzindex(HSV24 example)

bzverb(\
#include <blitz/array.h>

using namespace blitz;

class HSV24 {
public:
    // These constants will makes the code below cleaner; we can
    // refer to the components by name, rather than number.

    static const int hue=0, saturation=1, value=2;

    HSV24() { }
    HSV24(int hue, int saturation, int value)
      : h_(hue), s_(saturation), v_(value)
    { }

    // Some other stuff here, obviously

private:
    unsigned char h_, s_, v_;
};
)

Right after the class declaration, we will invoke the
macro tt(BZ_DECLARE_MULTICOMPONENT_TYPE) to tell Blitz++
about HSV24:

bzverb(\
// HSV24 has 3 components of type unsigned char
BZ_DECLARE_MULTICOMPONENT_TYPE(HSV24, unsigned char, 3);
)

Now we can create HSV images and modify the individual
components:

bzverb(\
int main()
{
    Array<HSV24,2> A(128,128);   // A 128x128 HSV image
    ...

    // Extract a greyscale version of the image
    Array<unsigned char,2> A_greyscale = A[HSV24::value];

    // Bump up the saturation component to get a
    // pastel effect
    A[HSV24::saturation] *= 1.3; 

    // Brighten up the middle of the image
    Range middle(32,96);
    A[HSV24::value](middle,middle) *= 1.2;
}
)

bzsubsect(Special support for complex arrays)

bzindex(Array!complex)
bzindex(complex arrays)

Since complex arrays are used frequently, Blitz++ provides
two special methods for getting the real and imaginary components:

bzverb(\
  Array<complex<float>,2> A(32,32);

  real(A) = 1.0;
  imag(A) = 0.0;
)

The function tt(real(A)) returns an array view of the
real component; tt(imag(A)) returns a view of the imaginary
component.

Note: Blitz++ provides numerous math functions defined
over complex-valued arrays, such as
tt(conj), tt(polar), tt(arg), tt(abs), tt(cos), tt(pow), etc.
See the section on math functions 
(ref(math-functions)) for details.

bzsubsect(Zipping together expressions)

bzindex(zipping expressions)
bzindex(Array!zipping expressions)
Blitz++ provides a function tt(zip()) which lets you
combine two or more expressions into a single component.
For example, you can combine two real expressions into
a complex expression, or three integer expressions into
an HSV24 expression.  The function has this syntax:

bzverb(\
resultexpr zip(expr1, expr2, T_element)
resultexpr zip(expr1, expr2, expr3, T_element)         ** not available yet
resultexpr zip(expr1, expr2, expr3, expr4, T_element)  ** not available yet
)

The types tt(resultexpr), tt(expr1) and tt(expr2) are
array expressions.  The third argument is the type you
want to create.  For example:

bzverb(\
int N = 16;
Array<complex<float>,1> A(N);
Array<float,1> theta(N);

 ...

A = zip(cos(theta), sin(theta), complex<float>());
)

The above line is equivalent to:

bzverb(\
for (int i=0; i < N; ++i)
   A[i] = complex<float>(cos(theta[i]), sin(theta[i]));
)

