/*!
\page tutorial PCIDSK API Tutorial

The PCIDSK file format is a geospatial file format which includes 
raster channels (or bands) and auxilary segments which include
information like georeferencing, color lookup tables, vector feature
data and many other special data types.  

The PCIDSK SDK provides C++ classes to interface to the various different
components of the file format.  The PCIDSKFile is used to interface with
the file as a whole.  The PCIDSKChannel is used to interface with a raster
channel (or band).  The PCIDSKSegment is the generic interface to 
auxilary segments.  There are additional interface classes available
for some of the specific segment types. 

\section tut_prelimin Include files, and Namespaces

The PCIDSK classes and interfaces are defined in a variety of 
include files, but generally it is sufficient to include just
the main include file, pcidsk.h.  

\code
#include <pcidsk.h>
\endcode

All PCIDSK classes are part of the C++ PCIDSK namespace.  It is often
convenient to use this namespace explicitly making all classes and
methods directly available.  This can be accomplished by putting the
follow declaration after the include of pcidsk.h.

\code
using namespace PCIDSK;
\endcode

However, for the balance of this tutorial we will explicitly include
the namespace when accessing classes to make it clearer which 
definitions are coming from the SDK. 

\section tut_open Opening the File

We start with a fairly trivial program using the SDK.  In this program
we open the desired file (irvine.pix), and print out general information
on the number of pixels, lines and channels.

\code
#include "gdal_priv.h"

int main()
{
    PCIDSK::PCIDSKFile *file = PCIDSK::Open( "irvine.pix", "r", NULL );

    printf( "File: %dC x %dR x %dC (%s)\n", 
            file->GetWidth(), file->GetHeight(), file->GetChannels(),
            file->GetInterleaving().c_str() );
    delete file;
}
\endcode

Note the use of the PCIDSK:: prefix for classes (like PCIDSKFile) and 
functions (like Open()) coming from the PCIDSK namespace.  The PCIDSK::Open
function is used to open the file, and various methods on the object are
used to get the number of pixels, lines and channels as well as the
interleaving.

The PCIDSK SDK API takes and returns strings using the std::string class,
so to get a C printable string out we use the c_str() method on the returned
string from the PCIDSK::PCIDSKFile::GetInterleaving() method. 

\section tut_readraster Reading Image Data

The PCIDSK::PCIDSKChannel class is used to interface with raster image
channels.  Normally raster access is accomplished one band at a time
as demonstrated in this snippit derived from tests/pcidsk_read.cpp.

\code
	for( int channel = 1; channel <= file->GetChannels(); channel++ )
        {
            PCIDSK::PCIDSKChannel *channel = file->GetChannel( channel );
            printf( "Channel %d of type %s.\n",
                    channel, 
                    PCIDSK::DataTypeName(channel->GetType()).c_str() );;

            int i_block;
            int x_block_count = 
                    (channel->GetWidth() + channel->GetBlockWidth()-1) 
                    / channel->GetBlockWidth();
            int y_block_count = 
                    (channel->GetHeight() + channel->GetBlockHeight()-1) 
                    / channel->GetBlockHeight();
            int block_size = PCIDSK::DataTypeSize(channel->GetType()) *
                    channel->GetBlockWidth() *
                    channel->GetBlockHeight();
            void *block_buffer = malloc( block_size );
            
            int block_count = x_block_count * y_block_count;
             
            for( i_block = 0; i_block < block_count; i_block++ )
            {
                channel->ReadBlock( i_block, block_buffer );
                /* ... do something with the imagery ... */
            }
            free( block_buffer );
        }
\endcode

Note that there is no effort to destroy the PCIDSKChannel object when
no longer needed.  Component objects like channels and segments are
owned by the PCIDSK::PCIDSKFile and should not be destroyed directly.
The accessors like GetChannel() return a pointer that remains owned
by the file. 

In this case we loop through all the channels, report the channel
number and type, and then loop through all the blocks in the channel
reading them.  For simplicity we don't actually do anything with them
here.  

The PCIDSK::PCIDSKChannel::ReadBlock() method is used to read 
imagery.  It reads exactly one block on the "natural block boundary"
and it is read in the original data type of the channel (8U, 16U, 16S
or 32R).  The blocking depends on the organization of the data on disk.
For pixel interleaved or band interleaved files this is one scanline
while for tiled files this is one tile.  The block size is established
with the PCIDSK::PCIDSKChannel::GetBlockWidth() and 
PCIDSK::PCIDSKChannel::GetBlockHeight() methods on the channel. The 
data type is determined with the PCIDSK::PCIDSKChannel::GetType() 
method.

The ReadBlock() method also has optional parameter to read a 
subwindow, but the PCIDSK SDK does *not* provide a generic
high level "read an arbitrary window of the image" method 
such as is provided by libraries like 
<a href="http://www.gdal.org/">GDAL</a> or PCI's own 
<a href="http://www.pcigeomatics.com/cgi-bin/pcihlp/GDBOpen">
GeoGateway/GDB</a>.
This is in keeping with the PCIDSK SDK policy of providing low
level "file organization oriented" data access with a minimum of
convenience services.  It is intended that higher level libraries
would provide caching, windowing and other convenience services.

*/
