Init from working directory of svn repository.
#include "system.h"
#include "RLEMap.h"
#include "RLEPair.h"
#include "tcl_interface.h"
#include "status_message.h"
/* *****************************************************************
* RLEMap.cc - Member functions for an RLEMap *
*
* RLEMap() - Constructor
* ~RLEMap() - Destructor
*
* int imageLength();
* int imageWidth();
* MapStatus & status;
*
* Below is an index of the other functions and the files where they
* appear.
*
* MapStatus readMap(char * filename) - RLEMap_readMap.cc
* MapStatus WriteMap(char * filename);
*
* // Data Access and low level manipulation functions
* RLEPairs * row(int i) - Returns a pointer to the list of RLEPairs
* for row i.
* MapStatus setBit(Point point, Color clr);
* Color readBit(Point point);
*
*
***************************************************************/
RLEMap::RLEMap()
: fMapData(NULL), fImageLength(0), fImageWidth(0), fStatus(EMPTY)
/*--------------------------------------------------------------
Primary Function: Constructor
Return Value: pointer to new RLEMap
Effects: Initialize status to empty other values to zero
Rev: 10/6/95 KM
---------------------------------------------------------------*/
{ }
RLEMap::~RLEMap()
/*--------------------------------------------------------------
Primary Purpose: destructor
Effects: Deletes each row of RLEPairs then the array of rows
Rev: 10/6/95 KM
---------------------------------------------------------------*/
{
if (fMapData != NULL)
{
int i;
// delete each row
for (i=0; i< fImageLength; i++)
{
delete fMapData[i];
}
// delete array of rows
delete fMapData;
}
};
int & RLEMap::imageLength()
/*--------------------------------------------------------------
Return Value: vertical length of image in pixels
Constraints: readMap() must have been run and fStatus be VALID
Rev: 10/6 KM
---------------------------------------------------------------*/
{
return fImageLength;
};
int & RLEMap::imageWidth()
/*--------------------------------------------------------------
Return Value: horizontal width of image in pixels
Constraints: readMap() must have been run and fStatus be valid
Rev: 10/20 KM
---------------------------------------------------------------*/
{
return fImageWidth;
}
MapStatus & RLEMap::status()
/*--------------------------------------------------------------
Return Value: return reference to current status EMPTY, VALID etc..
Rev: 10/6/95 KM
---------------------------------------------------------------*/
{
return fStatus;
}
RLEPairs * RLEMap::operator [](int i)
/*--------------------------------------------------------------
Arguments: i is the row # of the RLEPair list to be returned
Return Value: A pointer to the list of RLEPairs in row i
Rev: 10/20/95 KM
---------------------------------------------------------------*/
{
return fMapData[i];
}
RLEPairs * RLEMap::row(int i)
// Same as overloaded [] function above
{
return fMapData[i];
}
MapStatus RLEMap::readMap(char * filename)
/*--------------------------------------------------------------
Primary Purpose: Read an RLEMap from a TIFF file
Arguments: filename of TIFF file
Return Value: A MapStatus, either VALID or READERROR
Effects:
* RLEMap::readMap(filename) will read a two level TIFF file
* and place it in an RLEMap. The private fields of the RLEMap
* set are:
fImageWidth - the pixel width of the image
fImageLength - the vertical pixel length of the image
fstat - the status of the image VALID or READERROR
fMapData - an array of pointers to lists of RLEPairs
Constraints: filename must be a two level TIFF file
Rev: 10/20/95 Portions Borrowed from Assignment 1
---------------------------------------------------------------*/
{
TIFF *tif;
unsigned char * buf;
short photometric;
// Open File - Read length and width
tif = TIFFOpen (filename, "r");
if(tif == NULL)
return READERROR;
TIFFGetField (tif, TIFFTAG_IMAGELENGTH, &fImageLength);
TIFFGetField (tif, TIFFTAG_IMAGEWIDTH, &fImageWidth);
TIFFGetField (tif, TIFFTAG_PHOTOMETRIC, &photometric);
printf("open succeeded on file %s. length = %d. width = %d ",
filename, fImageLength, fImageWidth);
if(photometric == PHOTOMETRIC_MINISWHITE)
printf("min-is-white format\n");
else if(photometric == PHOTOMETRIC_MINISBLACK )
printf("min-is-black format\n");
else
printf("with an unknown photometric: %d\n", photometric);
// allocate buffer and array for data
int numCharsInBuf = fImageWidth / 8 +1 ;
buf = new unsigned char[numCharsInBuf];
fMapData = new (RLEPairs*)[fImageLength];
for (int row = 0; row < fImageLength; ++row)
{
TIFFReadScanline(tif,buf,row,0);
if(photometric != PHOTOMETRIC_MINISWHITE) /* invert anything except white */
invertBitsInBuffer(buf, numCharsInBuf);
// Create a list of RLEPairs for this row and fill with buffer data
fMapData[row] = new RLEPairs(row);
fMapData[row]->fill(buf, numCharsInBuf, row);
}
TIFFClose(tif);
return VALID;
}
short int RLEMap::grayScale(Point ul, Point lr)
// Dummy function for now
{
int numPixels = pixelsInRegion( ul, lr);
int area = (lr.x() - ul.x()+1) * (lr.y() - ul.y()+1);
if (area < numPixels) {
printf("Uh oh! Area = %d and pixels = %d\n", area, numPixels);
assert(area >= numPixels);
}
short int gscale =(short int)(((float)numPixels/area) * 255);
return gscale;
}
int RLEMap::pixelsInRegion(Point ul, Point lr)
{
assert (ul >= Point(0,0));
assert (ul <= lr);
assert (lr <= Point(fImageWidth, fImageLength));
int ulx = ul.x(); int uly = ul.y();
int lrx = lr.x(); int lry = lr.y();
int numPixels = 0;
RLEPairs * curRow;
for (int r = uly; r <= lry; r++)
{
curRow = row(r);
numPixels += curRow->pixelsBetween(ulx, lrx);
// cout << curRow->pixelsBetween(ulx,lrx) <<" ";
// cout << numPixels << endl;
}
return numPixels;
}
ListElement*
RLEMap::FindNearVertDot(int startCol, int endCol, int startRow, int endRow)
/*--------------------------------------------------------------
Primary Purpose: Return closest interval to startRow within bounds of
startCol and endRow in the direction of endRow. Finds
closest dot vertically from startRow.
Arguments: startRow is row to start from, startCol and endCol are
left and right boundaries of search. Search in the direction
of endRow.
Return Value: An RLE interval - pointer to a list element in RLEPairs
Effects:
Constraints: startRow < endRow
---------------------------------------------------------------*/
{
ListElement* current;
if (startRow < endRow) {
for (int i = startRow+2; i <= endRow; i++) {
current = fMapData[i]->first;
while (current != NULL) {
if ((((RLEPair *) current->item)->start <= endCol)
&& (((RLEPair *) current->item)->end >= startCol))
return current;
current = current->next;
}
}
} else {
for (int i = startRow-2; i >= endRow; i--) {
current = fMapData[i]->first;
while (current != NULL) {
if ((((RLEPair *) current->item)->start <= endCol)
&& (((RLEPair *) current->item)->end >= startCol))
return current;
current = current->next;
}
}
}
return NULL;
}
ListElement*
RLEMap::FindNearHorizDot(int startCol, int startRow, int endRow)
/*--------------------------------------------------------------
Primary Purpose: Return closest interval to startCol within bounds of
startRow and endRow (startRow is lower). Finds
closest dot horizontally from startCol.
Arguments: startCol is column to start from, startRow and endRow are
upper and lower boundaries of search
Return Value: An RLE interval - pointer to a list element in RLEPairs
Effects:
Constraints: startRow < endRow
---------------------------------------------------------------*/
{
ListElement* answer = NULL;
ListElement* current;
int closest = fImageWidth;
for (int i = startRow; i <= endRow; i++) {
current = fMapData[i]->first;
while ((current != NULL) && (((RLEPair *) current->item)->end
< startCol)) {
current = current->next;
}
if ((current != NULL) && (((RLEPair *) current->item)->start < closest)) {
answer = current;
closest = ((RLEPair *) answer->item)->start;
}
}
return answer;
}
void testRLEMap(char * filename)
/*--------------------------------------------------------------
Primary Purpose: Test the reading of tiff files into RLE format
Effects: Reads filename, puts it into RLE format then prints
Rev: 10/7/95 KM
---------------------------------------------------------------*/
{
RLEMap m;
m.readMap(filename);
if (m.imageLength() < 100) printMap(&m);
testpixelsBetween(&m); // In RLEPairs.cc - tests pixelsBetween function
}
void printMap(RLEMap * map)
{
int startX = 0;
int endX = 0;
int pos;
RLEPair * item;
RLEPairs * rowdata;
RLEMap & m = *map;
for (int r = 0; r < m.imageLength(); r++)
{
startX = 0;
endX = -1;
rowdata = m[r];
for (ListElement* ptr = rowdata->first; ptr != NULL; ptr = ptr->next)
{
item = (RLEPair *)(ptr->item);
startX = item->start;
for ( pos = endX+1; pos< startX; pos++)
cout << " ";
endX = item->end;
for ( pos = startX; pos <= endX; pos++)
cout << "X";
}
cout << "" << endl;
}
}
void RLEMap::printPairs(int startRow, int endRow)
/*--------------------------------------------------------------
Primary Purpose: Prints RLE Pairs for this map from startRow to endRow
Rev:11/2 KM
---------------------------------------------------------------*/
{
int startX, endX;
RLEPair * item;
RLEPairs * rowdata;
RLEMap & m = *this;
cout << "printing rows " << startRow << " to " << endRow << endl;
for (int r = startRow; r <= endRow; r++)
{
rowdata = m[r];
cout << "row " << r << " ";
for (ListElement *ptr = rowdata->first; ptr != NULL; ptr = ptr->next)
{
item = (RLEPair *)(ptr->item);
startX = item->start;
endX = item->end;
cout << "(" << startX << "," << endX <<")";
}
cout << endl;
}
}
void testpixelsBetween(RLEMap * map)
// tests out a row by making sure that pixels between
// 0 and ImageWidth - 1 == pixels in sub ranges of 29 pixels
// Test performed on center row.
{
int start = 0;
int end = 28;
int pcount;
int sum = 0;
RLEPairs * pairs;
int row;
for (row = 0; row < map->imageLength(); row++)
{
pairs = (*map)[row];
while (start <= map->imageWidth())
{
pcount = pairs->pixelsBetween(start, end);
// printf("row %d col %d to %d - %d pixels\n",row, start,end,pcount);
sum += pcount;
start +=29;
end +=29;
}
if (sum !=0)
printf("row %d sum was %d , should be %d\n", row, sum, pairs->numPixels);
assert(sum == pairs->numPixels);
start = 0;
end = 28;
sum = 0;
}
delete pairs;
}
int RLEMap::deskew()
/* going to be a (near-blind) steal from fateman */
/*--------------------------------------------------------------
Primary Purpose: deskewing an RLEMap
Arguments: none
Return Value: 1 if the page is altered, 0 if not
Effects: RLEMap is straightened out
Constraints: RLE shouldn't be tilted too much (< 10deg)
Rev: AR 11/1/95
---------------------------------------------------------------*/
{
double skew = -get_skew(this); /* skew in rad */
if((skew >= MINIMUM_SKEW_ANGLE)||(skew <= - MINIMUM_SKEW_ANGLE))
{
double h = tan(skew / (180 / M_PI));
if(h > 0)
{
tilt_and_slant(1/h, 1); /* clockwise */
return 1;
}
else if (h < 0)
{
tilt_and_slant(-(1/h), -1); /* counter clockwise */
return 1;
}
else
return 0;
}
else
return 0;
}
#define DEBUG_TILT_AND_SLANT 1
void RLEMap::tilt_and_slant(double step, int direction)
/*--------------------------------------------------------------
Primary Purpose: do the work of shifting the RLEMap
Arguments: step--something about how many rows to go before shifting,
direction--counterclockwise or clockwise
Return Value: none
Effects: rotates the RLEMap some ammount by tilting the map slightly,
then slanting it. (duh). Not an exact rotation
Constraints:
Rev: AR 11/1/95
---------------------------------------------------------------*/
{
if(DEBUG_TILT_AND_SLANT)
printf("Call to tilt_and_slant: step = %lf, direction = %d\n ", step, direction);
if(direction > 0)
{
tilt(step, direction);
slant(step, direction);
}
else
{
slant(step, -direction);
tilt(step, direction);
}
}
#define DEBUG_SLANT 1
/* "slant a picture by shifting lines horizontally 1 bit every step rows"
;; dir 1 means shift to right as row number increases
;; dir -1 means shift by left
;; this does not rotate the picture, since rows are each unchanged.
;; the effect of a positive direction, say (slantpic pic 3 3 1)
;; is to "italicize".
*/
void RLEMap::slant(double step, int direction)
{
if(DEBUG_SLANT)
printf("Slant called, step = %lf, dir = %d\n", step, direction);
fImageWidth += (int)((double)fImageLength / (double)step);
int shift_amount = direction;
int num_steps = 1;
for(int i = 0; i < fImageLength; i++)
{
if(i > (num_steps*(int)step))
/* if we have gone through step rows, increment the shift */
{
shift_amount += direction;
num_steps++;
}
/* printf("Shifting row %d by %d\n", i, shift_amount); */
fMapData[i]->shift(shift_amount);
}
}
void RLEMap::display_intervals(char* color)
{
if(!DISPLAY_IMAGE)
return;
double skip;
last_status = 0.0;
printf("SCALE_FACTOR = %lf ", SCALE_FACTOR);
skip = 1.0 / SCALE_FACTOR;
printf("Skip = %lf\n", skip);
/* delete any garbage hanging around */
docommand(".main_window.display.work_space delete all");
set_status("Displaying Image: 0%...");
for(int i= 0; (int)(i*skip) < ((double)fImageLength); i++)
{
set_display_status((int)(i*skip), fImageLength);
fMapData[(int)(i*skip)]->draw_pairs(i, color, 1.0/skip);
}
last_status = 0.0;
update();
set_status("Displaying Image: Done");
}
void RLEMap::tilt(double step, int direction)
{
/* printf("tilt called, step = %lf, dir = %d\n", step, direction); */
int old_height = fImageLength;
int new_height = /* ceiling */ (int)(((double)fImageWidth) / step) + old_height;
int delta = old_height - new_height;
RLEPairs ** new_data = new RLEPairs*[new_height];
for(int i = 0; i < new_height; i++)
{
new_data[i] = new RLEPairs(i);
}
for(int j = 0; j < old_height; j++)
{
tilt_row(j, delta, new_data, step, direction);
}
fMapData = new_data; /* probably want to delete old data */
fImageLength = new_height;
display_intervals("black");
}
void RLEMap::tilt_row(int old_row_index, int old_new_row_diff, RLEPairs** new_data, double step, int direction)
{
/* printf("Tilt row called: old row = %d, row diff = %d, step = %lf, dir = %d\n", old_row_index, old_new_row_diff, step, direction); */
double cur_x = 0; /* I don't know what will happen with negative rows */
double new_x;
int cur_y = old_row_index + (old_new_row_diff * direction);
while(((new_x = cur_x + step) < fImageWidth) &&
(cur_y >= 0) && (cur_y < fImageLength))
{
RLEPairs* new_pairs;
new_pairs = (fMapData[old_row_index])->extract((int) cur_x, (int)new_x);
new_data[cur_y]->merge(new_pairs);
cur_x = new_x + 1;
cur_y += direction;
}
}