text: /******************************************************************************
   * Program: GlobalCoordinatesToFileMapper
   * Module:  GlobalCoordinatesToFileMapper.cpp
   * Authors: Nicholas Schwarz, schwarz@evl.uic.edu
   * Date:    21 September 2004
   *
   * Copyright (C) 2004 Electronic Visualization Laboratory,
   * University of Illinois at Chicago
   *
   * All rights reserved.
   *
   * Redistribution and use in source and binary forms, with or without
   * modification, are permitted provided that the following conditions are met:
   *
   *  * Redistributions of source code must retain the above copyright
   *    notice, this list of conditions and the following disclaimer.
   *  * Redistributions in binary form must reproduce the above
   *    copyright notice, this list of conditions and the following disclaimer
   *    in the documentation and/or other materials provided with the distribution.
   *  * Neither the name of the University of Illinois at Chicago nor
   *    the names of its contributors may be used to endorse or promote
   *    products derived from this software without specific prior written permission.
   *
   * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
   * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
   * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
   * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
   * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
   * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
   * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
   * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
   * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
   * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
   * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
   *
   * Direct questions, comments etc to schwarz@evl.uic.edu or
   * http://www.evl.uic.edu/cavern/forum/
   *
   *****************************************************************************/
  
  
  // Include header file for this class
  #include "GlobalCoordinatesToFileMapper.h"
  
  
  //-----------------------------------------------------------------------------
  GlobalCoordinatesToFileMapper::GlobalCoordinatesToFileMapper()
  {
  
    // Initialize global image description to NULL.
    this -> Description = NULL;
  
    // Initialize file coordinate dimensions to 0 by 0.
    this -> FileCoordinateDimensions[0] = 0;
    this -> FileCoordinateDimensions[1] = 0;
  
    // Initialize global coordinate dimensions to 0 by 0.
    this -> GlobalCoordinateDimensions[0] = 0;
    this -> GlobalCoordinateDimensions[1] = 0;
  
    // Initalize global file layour array to NULL.
    this -> GlobalFileLayoutArray = NULL;
  
    // Initialize global file layout dimensions to 0.
    this -> GlobalFileLayoutDimensions[0] = 0;
    this -> GlobalFileLayoutDimensions[1] = 0;
  
    // Initialize the initialized flag to false.
    this -> Initialized = false;
  
    // Initialize the query extent.
    this -> QueryExtent[0] = 0;
    this -> QueryExtent[1] = 0;
    this -> QueryExtent[2] = 0;
    this -> QueryExtent[3] = 0;
  
    // Initialize the query file info array to NULL.
    this -> QueryFileInfoArray = NULL;
  
    // Initialize the query file info array dimensions to 0 by 0.
    this -> QueryFileInfoDimensions[0] = 0;
    this -> QueryFileInfoDimensions[1] = 0;
  
  }
  
  
  //-----------------------------------------------------------------------------
  const char* GlobalCoordinatesToFileMapper::GetDescription()
  {
  
    // Return pointer to global image description.
    return this -> Description;
  
  }
  
  
  //-----------------------------------------------------------------------------
  long GlobalCoordinatesToFileMapper::GetFileCoordinateDimensionH()
  {
  
    // Return FileCoordinateDimensionH
    return this -> FileCoordinateDimensions[1];
  
  }
  
  
  //-----------------------------------------------------------------------------
  long GlobalCoordinatesToFileMapper::GetFileCoordinateDimensionW()
  {
  
    // Return FileCoordinateDimensionW
    return this -> FileCoordinateDimensions[0];
  
  }
  
  
  //-----------------------------------------------------------------------------
  long GlobalCoordinatesToFileMapper::GetGlobalCoordinateDimensionH()
  {
  
    // Return GlobalCoordinateDimensionH
    return this -> GlobalCoordinateDimensions[1];
  
  }
  
  
  //-----------------------------------------------------------------------------
  long GlobalCoordinatesToFileMapper::GetGlobalCoordinateDimensionW()
  {
  
    // Return GlobalCoordinateDimensionW
    return this -> GlobalCoordinateDimensions[0];
  
  }
  
  
  //-----------------------------------------------------------------------------
  long GlobalCoordinatesToFileMapper::GetGlobalCoordinates(const char* name,
  							 long* x,
  							 long* y,
  							 long* w,
  							 long* h)
  {
  
    // Check if instance is initialized
    if (this -> Initialized == false)
      {
        return GLOBAL_COORDINATES_TO_FILE_MAPPER_ERROR_NOT_INITIALIZED;
      }
  
    // Loop through the global file layout array.
    for (long c = 0, p = 0 ; c < GlobalFileLayoutDimensions[0] ; c++)
      {
        for (long r = 0 ; r < GlobalFileLayoutDimensions[1] ; r++, p++)
  	{
  	  // Check for given file.
  	  if (strcmp(this -> GlobalFileLayoutArray[p], name) == 0)
  	    {
  	      *x = this -> FileCoordinateDimensions[0] * c;
  	      *y = this -> FileCoordinateDimensions[1] * r;
  	      *w = this -> FileCoordinateDimensions[0];
  	      *h = this -> FileCoordinateDimensions[1];
  	      return GLOBAL_COORDINATES_TO_FILE_MAPPER_SUCCESS;
  	    }
  	}
      }
  
    // Return error is the file does not exist in the mapper.
    return GLOBAL_COORDINATES_TO_FILE_MAPPER_ERROR_INVALID_FILE;
  
  }
  
  
  //-----------------------------------------------------------------------------
  char** GlobalCoordinatesToFileMapper::GetGlobalFileLayoutArray(long* cols,
  							       long* rows)
  {
  
    // GlobalFileLayoutDimensions
    *cols = this -> GlobalFileLayoutDimensions[0];
    *rows = this -> GlobalFileLayoutDimensions[1];
  
    // Return pointer to the global file layout array
    return this -> GlobalFileLayoutArray;
  
  }
  
  
  //-----------------------------------------------------------------------------
  void GlobalCoordinatesToFileMapper::GetGlobalFileLayoutDimensions(long* cols,
  								  long* rows)
  {
  
    // GlobalFileLayoutDimensions
    *cols = this -> GlobalFileLayoutDimensions[0];
    *rows = this -> GlobalFileLayoutDimensions[1];
  
    return;
  
  }
  
  
  //-----------------------------------------------------------------------------
  long GlobalCoordinatesToFileMapper::GetQueryExtentH()
  {
  
    // Return QueryExtentH
    return this -> QueryExtent[3];
  
  }
  
  
  //-----------------------------------------------------------------------------
  long GlobalCoordinatesToFileMapper::GetQueryExtentW()
  {
  
    // Return QueryExtentW
    return this -> QueryExtent[2];
  
  }
  
  
  //-----------------------------------------------------------------------------
  long GlobalCoordinatesToFileMapper::GetQueryExtentX()
  {
  
    // Return QueryExtentH
    return this -> QueryExtent[0];
  
  }
  
  
  //-----------------------------------------------------------------------------
  long GlobalCoordinatesToFileMapper::GetQueryExtentY()
  {
  
    // Return QueryExtentH
    return this -> QueryExtent[1];
  
  }
  
  
  //-----------------------------------------------------------------------------
  FileInfo* GlobalCoordinatesToFileMapper::GetQueryFileInfoArray(long* cols,
  							       long* rows)
  {
  
    // QueryFileInfoArray dimensions
    *cols = this -> QueryFileInfoDimensions[0];
    *rows = this -> QueryFileInfoDimensions[1];
  
    // Return QueryFileInfoArray
    return this -> QueryFileInfoArray;
  
  }
  
  
  //-----------------------------------------------------------------------------
  void GlobalCoordinatesToFileMapper::GetQueryFileInfoDimensions(long* cols,
  							       long* rows)
  {
  
    // QueryFileInfoArray dimensions
    *cols = this -> QueryFileInfoDimensions[0];
    *rows = this -> QueryFileInfoDimensions[1];
  
    return;
  
  }
  
  
  //-----------------------------------------------------------------------------
  int GlobalCoordinatesToFileMapper::Initialize(const char* name)
  {
  
    // Try to open file for reading.
    ifstream file(name);
  
    // Check if file is open.
    if (!file.is_open())
      {
        return GLOBAL_COORDINATES_TO_FILE_MAPPER_ERROR_INVALID_FILE;
      }
  
    // Read GlobalCoordinateDimensions, GlobalFileLayoutDimensions, and
    // FileCoordinateDimensions, respectively.
    file >> this -> GlobalCoordinateDimensions[0]
         >> this -> GlobalCoordinateDimensions[1]
         >> this -> GlobalFileLayoutDimensions[0]
         >> this -> GlobalFileLayoutDimensions[1]
         >> this -> FileCoordinateDimensions[0]
         >> this -> FileCoordinateDimensions[1];
  
    // Allocate storage for the GlobalFileLayoutArray
    this -> GlobalFileLayoutArray =
      new char*[GlobalFileLayoutDimensions[0] * GlobalFileLayoutDimensions[1]];
  
    // Read each file in the global image in order. Entries in the file are
    // column by column.
    for (long i = 0 ;
         i < GlobalFileLayoutDimensions[0] * GlobalFileLayoutDimensions[1] ;
         i++)
      {
        this -> GlobalFileLayoutArray[i] = new char[100];
        file >> this -> GlobalFileLayoutArray[i];
      }
  
    // Close file
    file.close();
  
    // Set initialized to true
    this -> Initialized = true;
  
    // Return successfully
    return GLOBAL_COORDINATES_TO_FILE_MAPPER_SUCCESS;
  
  }
  
  
  //-----------------------------------------------------------------------------
  bool GlobalCoordinatesToFileMapper::IsInitialized()
  {
  
    // Return Initialized
    return this -> Initialized;
  
  }
  
  
  //-----------------------------------------------------------------------------
  void GlobalCoordinatesToFileMapper::PrintSelf(ostream& os)
  {
  
    os << "GlobalCoordinatesToFileMapper - Begin PrintSelf ------------------\n";
  
    if (this -> Description != NULL)
      os << "  Description: " << this -> Description << "\n";
    else
      os << "  Description: null\n";
  
    os << "  File Coordinate Dimensions: "
       << this -> FileCoordinateDimensions[0] << " "
       << this -> FileCoordinateDimensions[1] << "\n";
  
    os << "  Global Coordinate Dimensions: "
       << this -> GlobalCoordinateDimensions[0] << " "
       << this -> GlobalCoordinateDimensions[1] << "\n";
  
    os << "  Global File Layout Array:\n";
    for (long i = 0 ;
         i < this -> GlobalFileLayoutDimensions[0] *
  	 GlobalFileLayoutDimensions[1] ;
         i++)
      {
        if (this -> GlobalFileLayoutArray != NULL)
  	{
  	  if (this -> GlobalFileLayoutArray[i] != NULL)
  	    {
  	      os << "    " << this -> GlobalFileLayoutArray[i] << "\n";
  	    }
  	  else
  	    {
  	      os << "    null" << endl;
  	    }
  	}
      }
  
    os << "  Global File Layout Dimensions: "
       << this -> GlobalFileLayoutDimensions[0] << " "
       << this -> GlobalFileLayoutDimensions[1] << "\n";
  
    os << "  Query Extent: "
       << this -> QueryExtent[0] << " "
       << this -> QueryExtent[1] << " "
       << this -> QueryExtent[2] << " "
       << this -> QueryExtent[3] << "\n";
  
    os << "  Query File Info Dimensions: "
       << this -> QueryFileInfoDimensions[0] << " "
       << this -> QueryFileInfoDimensions[1] << "\n";
  
    os << "GlobalCoordinatesToFileMapper - End PrintSelf --------------------\n"
       << endl;
  
    return;
  
  }
  
  
  //-----------------------------------------------------------------------------
  int GlobalCoordinatesToFileMapper::Query()
  {
  
    // Check if instance is initialized
    if (this -> Initialized == false)
      {
        return GLOBAL_COORDINATES_TO_FILE_MAPPER_ERROR_NOT_INITIALIZED;
      }
  
    // Check that query extent is within global image bounds
    if ((this -> QueryExtent[0] + this -> QueryExtent[2] >
         this -> GlobalCoordinateDimensions[0]) ||
        (this -> QueryExtent[1] + this -> QueryExtent[3] >
         this -> GlobalCoordinateDimensions[1]))
      {
        return GLOBAL_COORDINATES_TO_FILE_MAPPER_ERROR_INVALID_EXTENT;
      }
  
    // Calculate the first column and row
    long fc = this -> QueryExtent[0] / this -> FileCoordinateDimensions[0];
    long fr = this -> QueryExtent[1] / this -> FileCoordinateDimensions[1];
  
    // Calculate the last column and row
    long lc = (this -> QueryExtent[0] + this -> QueryExtent[2]) /
      this -> FileCoordinateDimensions[0];
    long lr = (this -> QueryExtent[1] + this -> QueryExtent[3]) /
      this -> FileCoordinateDimensions[1];
  
    // Set the query file info dimensions
    this -> QueryFileInfoDimensions[0] = lc - fc + 1;
    this -> QueryFileInfoDimensions[1] = lr - fr + 1;
  
    // Calculate the total number of files in the result
    long tot = (lc - fc + 1) * (lr - fr + 1);
  
    // Delete previous query result.
    if (this -> QueryFileInfoArray != NULL)
      {
        delete [] this -> QueryFileInfoArray;
      }
  
    // Allocate storage for new query.
    this -> QueryFileInfoArray = new FileInfo[tot];
  
    // Count number of files in FileInfoArray
    long fcnt = 0;
  
    // Create FileInfoArray for query. Loop through each column, and row
    // of the global array specified by the bounds computed above, filling in
    // the array. This probably isn't the best way to do this, but it's what
    // I came up with in one night.
    for (long cgc = fc, clc = 0 ; cgc <= lc ; cgc++, clc++)
      {
        for (long cgr = fr, clr = 0 ; cgr <= lr ; cgr++, clr++)
  	{
  	  // Set file dimensions
  	  this -> QueryFileInfoArray[fcnt].
  	    SetDimensions(this -> FileCoordinateDimensions[0],
  			  this -> FileCoordinateDimensions[1]);
  
  	  // Determine file's position in global array
  	  long pos = (cgc * this -> GlobalFileLayoutDimensions[1]) + cgr;
  
  	  // Calculate and set the extent for the current individual file.
  
  	  // first and last column
  	  if (clc == 0 && lc - fc == 0)
  	    {
  	      if (this -> QueryExtent[0] >=
  		  this -> FileCoordinateDimensions[0])
  		{
  		  this -> QueryFileInfoArray[fcnt].
  		    SetExtentX(this -> QueryExtent[0] -
  			       (cgc * this -> FileCoordinateDimensions[0]));
  		}
  	      else
  		{
  		  this -> QueryFileInfoArray[fcnt].SetExtentX(this ->
  							      QueryExtent[0]);
  		}
  	      this -> QueryFileInfoArray[fcnt].SetExtentW(this ->
  							  QueryExtent[2]);
  	    }
  
  	  // first and last row
  	  if (clr == 0 && lr - fr == 0)
  	    {
  	      // if first row is from 0 then it's OK, but if it's not
  	      // then subtract number of rows * fileDim
  	      if (this -> QueryExtent[1] >=
  		  this -> FileCoordinateDimensions[1])
  		{
  		  this -> QueryFileInfoArray[fcnt].
  		    SetExtentY(this -> QueryExtent[1] -
  			       (cgr * this -> FileCoordinateDimensions[1]));
  		}
  	      else
  		{
  		  this -> QueryFileInfoArray[fcnt].SetExtentY(this ->
  							      QueryExtent[1]);
  		}
  	      this -> QueryFileInfoArray[fcnt].SetExtentH(this ->
  							  QueryExtent[3]);
  
  	    }
  
  	  // first, but not last, column
  	  if (clc == 0 && lc - fc != 0)
  	    {
  	      long tmp = this -> QueryExtent[0] -
  		(cgc * this -> FileCoordinateDimensions[0]);
  	      this -> QueryFileInfoArray[fcnt].SetExtentX(tmp);
  	      this -> QueryFileInfoArray[fcnt].
  		SetExtentW(this -> FileCoordinateDimensions[0] - tmp);
  	    }
  
  	  // first, but not last, row
  	  if (clr == 0 && lr - fr != 0)
  	    {
  	      long tmp = this -> QueryExtent[1] -
  		(cgr * this -> FileCoordinateDimensions[1]);
  	      this -> QueryFileInfoArray[fcnt].SetExtentY(tmp);
  	      this -> QueryFileInfoArray[fcnt].
  		SetExtentH(this -> FileCoordinateDimensions[1] - tmp);
  	    }
  
  	  // last, but not only, column
  	  if (clc == (lc - fc) && clc != 0)
  	    {
  	      long tmp = (this -> QueryExtent[0] + this -> QueryExtent[2]) -
  		(cgc * this -> FileCoordinateDimensions[0]);
  	      this -> QueryFileInfoArray[fcnt].SetExtentX(0);
  	      this -> QueryFileInfoArray[fcnt].SetExtentW(tmp);
  	    }
  
  	  // last, but not only, row
  	  if (clr == (lr - fr) && clr != 0)
  	    {
  	      long tmp = (this -> QueryExtent[1] + this -> QueryExtent[3]) -
  		(cgr * this -> FileCoordinateDimensions[1]);
  	      this -> QueryFileInfoArray[fcnt].SetExtentY(0);
  	      this -> QueryFileInfoArray[fcnt].SetExtentH(tmp);
  	    }
  
  	  // Not the first and not the last column
  	  if (clc != 0 && clc != (lc - fc))
  	    {
  	      this -> QueryFileInfoArray[fcnt].SetExtentX(0);
  	      this -> QueryFileInfoArray[fcnt].
  		SetExtentW(this -> FileCoordinateDimensions[0]);
  	    }
  
  	  // Not the first and not the last row
  	  if (clr != 0 && clr != (lr - fr))
  	    {
  	      this -> QueryFileInfoArray[fcnt].SetExtentY(0);
  	      this -> QueryFileInfoArray[fcnt].
  		SetExtentH(this -> FileCoordinateDimensions[1]);
  	    }
  
  	  // Set file name
  	  this -> QueryFileInfoArray[fcnt].
  	    SetFileName(this -> GlobalFileLayoutArray[pos]);
  
  	  // Set local file position to current local column,
  	  // current local row.
  	  this -> QueryFileInfoArray[fcnt].SetLocalPosition(clc, clr);
  
  	  // Increment number of files in FileInfoArray
  	  fcnt++;
  	}
      }
  
    // Return successfully
    return GLOBAL_COORDINATES_TO_FILE_MAPPER_SUCCESS;
  
  }
  
  
  //-----------------------------------------------------------------------------
  void GlobalCoordinatesToFileMapper::SetDescription(const char* string)
  {
  
    // Delete current description.
    if (this -> Description != NULL)
      {
        delete [] this -> Description;
        this -> Description = NULL;
      }
  
    // Copy string as new description.
    if (string != NULL)
      {
        this -> Description = new char[strlen(string) + 1];
        strcpy(this -> Description, string);
      }
  
    return;
  
  }
  
  
  //-----------------------------------------------------------------------------
  void GlobalCoordinatesToFileMapper::SetFileCoordinateDimensions(long w,
  								long h)
  {
  
    // Set FileCoordinateDimensions
    this -> FileCoordinateDimensions[0] = w;
    this -> FileCoordinateDimensions[1] = h;
  
    return;
  
  }
  
  
  //-----------------------------------------------------------------------------
  void GlobalCoordinatesToFileMapper::SetInitializedFalse()
  {
  
    // Set Initialized to false.
    this -> Initialized = false;
  
    return;
  
  }
  
  
  //-----------------------------------------------------------------------------
  void GlobalCoordinatesToFileMapper::SetInitializedTrue()
  {
  
    // Set Initialized to true.
    this -> Initialized = true;
  
    return;
  
  }
  
  
  //-----------------------------------------------------------------------------
  void GlobalCoordinatesToFileMapper::SetGlobalCoordinateDimensions(long w,
  								  long h)
  {
  
    // Set GlobalCoordinateDimensions
    this -> GlobalCoordinateDimensions[0] = w;
    this -> GlobalCoordinateDimensions[1] = h;
  
    return;
  
  }
  
  
  //-----------------------------------------------------------------------------
  void GlobalCoordinatesToFileMapper::SetGlobalFileLayoutArray(char** array,
  							     long cols,
  							     long rows)
  {
  
    // Set GlobalFileLayoutDimensions
    this -> GlobalFileLayoutDimensions[0] = cols;
    this -> GlobalFileLayoutDimensions[1] = rows;
  
    return;
  
  }
  
  
  //-----------------------------------------------------------------------------
  void GlobalCoordinatesToFileMapper::SetGlobalFileLayoutDimensions(long cols,
  								  long rows)
  {
  
    // Set GlobalFileLayoutDimensions
    this -> GlobalFileLayoutDimensions[0] = cols;
    this -> GlobalFileLayoutDimensions[1] = rows;
  
    return;
  
  }
  
  
  //-----------------------------------------------------------------------------
  void GlobalCoordinatesToFileMapper::SetQueryExtent(long x, long y,
  						   long w, long h)
  {
  
    // Set QueryExtent
    this -> QueryExtent[0] = x;
    this -> QueryExtent[1] = y;
    this -> QueryExtent[2] = w;
    this -> QueryExtent[3] = h;
  
    return;
  
  }
  
  
  //-----------------------------------------------------------------------------
  void GlobalCoordinatesToFileMapper::SetQueryFileInfoArray(FileInfo* array,
  							  long cols,
  							  long rows)
  {
  
    // Check if an array exists, and if so delete it.
    if (this -> QueryFileInfoArray != NULL)
      {
        delete [] this -> QueryFileInfoArray;
      }
  
    // Assigned array. NOTE: This is bad, very, very bad. Should be a deep
    // copy operation.
    this -> QueryFileInfoArray = array;
  
    // Set QueryFileInfoDimensions
    this -> QueryFileInfoDimensions[0] = cols;
    this -> QueryFileInfoDimensions[1] = rows;
  
    return;
  
  }
  
  
  //-----------------------------------------------------------------------------
  void GlobalCoordinatesToFileMapper::SetQueryFileInfoDimensions(long cols,
  							       long rows)
  {
  
    // Set QueryFileInfoDimensions
    this -> QueryFileInfoDimensions[0] = cols;
    this -> QueryFileInfoDimensions[1] = rows;
  
    return;
  
  }
  
  
  //-----------------------------------------------------------------------------
  GlobalCoordinatesToFileMapper::~GlobalCoordinatesToFileMapper()
  {
  
    // Deallocate memory used for description.
    if (this -> Description != NULL)
      {
        delete [] this -> Description;
      }
  
    // Deallocate memory used for the GlobalFileLayoutArray
    if (this -> GlobalFileLayoutArray != NULL)
      {
        for (long i = 0 ;
  	   i < this -> GlobalFileLayoutDimensions[0] *
  	     this -> GlobalFileLayoutDimensions[1] ;
  	   i++)
  	{
  	  if (this -> GlobalFileLayoutArray[i] != NULL)
  	    {
  	      delete [] this -> GlobalFileLayoutArray[i];
  	    }
  	}
        delete [] this -> GlobalFileLayoutArray;
      }
  
    // Deallocate memory for QueryFileInfoArray
    if (this -> QueryFileInfoArray != NULL)
      {
        delete [] this -> QueryFileInfoArray;
      }
  
  }
  