/*!
  \param     map PCRaster map handle. It is ours to close.
*/
PCRasterDataset::PCRasterDataset(
         MAP* map)

  : GDALPamDataset(),
    d_map(map), d_west(0.0), d_north(0.0), d_cellSize(0.0)

{
  // Read header info.
  nRasterXSize = RgetNrCols(d_map);
  nRasterYSize = RgetNrRows(d_map);
  d_west = static_cast<double>(RgetXUL(d_map));
  d_north = static_cast<double>(RgetYUL(d_map));
  d_cellSize = static_cast<double>(RgetCellSize(d_map));
  d_cellRepresentation = RgetUseCellRepr(d_map);
  CPLAssert(d_cellRepresentation != CR_UNDEFINED);
  d_valueScale = RgetValueScale(d_map);
  CPLAssert(d_valueScale != VS_UNDEFINED);
  d_defaultNoDataValue = ::missingValue(d_cellRepresentation);
  d_location_changed = false;

  // Create band information objects.
  nBands = 1;
  SetBand(1, new PCRasterRasterBand(this));

  SetMetadataItem("PCRASTER_VALUESCALE", valueScale2String(
         d_valueScale).c_str());
}
Beispiel #2
0
/* make all cells missing value in map
 * RputAllMV writes a missing values to all the cells in a
 * map. For this is allocates a buffer to hold one row at a
 * time.
 * returns 1 if succesfull, 0 in case of an error
 */
int RputAllMV(
	MAP *m)
{
	size_t i,nc,nr;
	void *buffer;
	CSF_CR cr;

	CHECKHANDLE_GOTO(m, error);
	if(! WRITE_ENABLE(m))
	{
		M_ERROR(NOACCESS);
		goto error;
	}

	cr = RgetCellRepr(m);
	nc = RgetNrCols(m);

	buffer = Rmalloc(m,nc);
	if(buffer == NULL)
	{
		M_ERROR(NOCORE);
		goto error;
	}

	/*  Fill buffer with determined Missingvalue*/
	SetMemMV(buffer, nc, cr);

	nr = RgetNrRows(m);
	for(i = 0 ; i < nr; i++)
	 if (RputRow(m, i, buffer) != nc)
	 {
	    M_ERROR(WRITE_ERROR);
	    goto error_f;
	 }
	CSF_FREE(buffer);

	CsfSetVarTypeMV( &(m->raster.minVal), cr);
	CsfSetVarTypeMV( &(m->raster.maxVal), cr);

	return(1);
error_f:  
	CSF_FREE(buffer);
error:
	return(0);
}
Beispiel #3
0
static int ReadAttr(
       ATTRIBUTES *a,
       MAP *m,
       BOOL readOnly) /* are the attribute only used for teh PRINT op
                       */
{
       DefaultAttr(a);
       if (RuseAs(m, CR_REAL8))
              goto failure;
        RgetMinVal(m, &(a->minVal));
        RgetMaxVal(m, &(a->maxVal));
        a->projection = MgetProjection(m);
        a->xUL = RgetXUL(m);
        a->yUL = RgetYUL(m);
       a->nrRows = RgetNrRows(m);
       a->nrCols = RgetNrCols(m);
       a->cellSize = RgetCellSize(m);
        a->version    = MgetVersion(m);
       a->gisFileId = MgetGisFileId(m);
       a->byteOrder = m->main.byteOrder;
       a->attrTable = m->main.attrTable;
       if (Merrno)
              goto failure;
       if (a->version == 2 || readOnly)
       { /* otherwise use defaults */
          a->valueScale = RgetValueScale(m);
          a->cellRepr = RgetCellRepr(m);
         a->angle = RgetAngle(m);
         if (a->angle < 0)
             a->angle = -Rad2Deg(-a->angle);
         else
             a->angle = Rad2Deg(a->angle);
       }
       return 0;
failure:
       return 1;
}
Beispiel #4
0
/* Calculates one pixel from output map, given the input maps.
 * Puts all values of input pixels in a list and determines the value of
 * the output pixel according to these values and the overlapping areas.
 * Returns 0 if no error occurs, 1 otherwise.
 */
static int CalcPixel(
	MAP *out,		/* write-only output map */
 	MAP **in,		/* read-only list input maps */
 	size_t nrCoverCells,	/* min. nr. non-MV cells for non-MV */
 	size_t nrMaps,		/* nr. of input maps */
 	double rOut,		/* row number pixel */
 	double cOut,		/* column number pixel */
 	BOOL aligned,		/* maps are aligned */
 	REAL8 angle)		/* angle of output map */
{		
	PTYPE 	tlX, tlY, trX, trY, brX, brY, blX, blY;
	double 	r, c;
	DATA 	*list = NULL;  	/* areas and values of input cells */
   	size_t 	i, nrList = 0;	/* number of items in list */
	POINT2D 	*outputCell;	/* polygon of output cell */
   	size_t 	nr = 4;		/* nr of points of cell */
   	CSF_VS	vs;		/* value scale of first input map */

	if(nrCoverCells > 0 && nrMaps > 1)
		raster = InitRaster(raster); /* initialize the raster */

   	/* Determine the four corners of output pixel */
   	RrowCol2Coords(out, rOut, cOut, &tlX, &tlY); /* top left */
   	RrowCol2Coords(out, rOut, cOut + 1, &trX, &trY); /* top right */
   	RrowCol2Coords(out, rOut + 1, cOut, &blX, &blY); /* bottom left */
   	RrowCol2Coords(out, rOut + 1, cOut + 1, &brX, &brY); /* bottom right */
	outputCell = PutInPol(tlX, tlY, trX, trY, brX, brY, blX, blY);
	if(outputCell == NULL)
		return 1;

	POSTCOND(outputCell[0].x == outputCell[nr].x);
	POSTCOND(outputCell[0].y == outputCell[nr].y);

	/* Get pixel on every input map */
	for(i = 0; i < nrMaps; i++)
	{
		MAP 	*X = in[i];	/* input map number i */
		PTYPE 	tlC, tlR, trC, trR, brC, brR, blC, blR;
		PTYPE 	tlX2, tlY2, trX2, trY2, brX2, brY2, blX2, blY2;
   		double 	leftB, belowB, rightB, upperB;	/* boundaries */

		/* Corners: (tlX, tlY), (trX, trY), (blX, blY) and
		 * (brX, brY). Translate for input map.
		 */
   		Rcoords2RowCol(X, tlX, tlY, &tlC, &tlR); /* top left */
   		Rcoords2RowCol(X, trX, trY, &trC, &trR); /* top right */
   		Rcoords2RowCol(X, blX, blY, &blC, &blR); /* bottom left */
   		Rcoords2RowCol(X, brX, brY, &brC, &brR); /* bottom right */

   		/* Boundaries in the input map */
   		rightB = ceil(MaxPoint(tlR, trR, blR, brR));	
   		belowB = ceil(MaxPoint(tlC, trC, blC, brC));	
   		leftB = floor(MinPoint(tlR, trR, blR, brR));	
   		upperB = floor(MinPoint(tlC, trC, blC, brC));	
   		
		PRECOND(upperB <= belowB);
		PRECOND(leftB <= rightB);

		/* Check all cells between the boundaries */
		for(r = upperB; r < belowB; r++)
		{
			REAL8 *currRow;
			if(0 <= r && r <= RgetNrRows(X))
		 	 currRow = (REAL8 *)CacheGetRow(in, i,  r);

			for(c = leftB; c < rightB; c++)
		 	{  /* Cells that might be in pixel */
   			    POINT2D *inputCell;  /* polygon input cell */

			    if(r < 0 || RgetNrRows(X) <= r || c < 0 ||
			       RgetNrCols(X) <= c)
			    	continue;

   			    /* Top left & right, bottom left & right */
   			    RrowCol2Coords(X, r, c, &tlX2, &tlY2);
   			    RrowCol2Coords(X, r, c+1, &trX2, &trY2);
   			    RrowCol2Coords(X, r+1, c, &blX2, &blY2);
   			    RrowCol2Coords(X, r+1, c+1, &brX2, &brY2);
			    inputCell = PutInPol(tlX2, tlY2, trX2, trY2,
					brX2, brY2, blX2, blY2);
			    if(inputCell == NULL)
				return 1;

			    POSTCOND(inputCell[0].x == inputCell[nr].x);
			    POSTCOND(inputCell[0].y == inputCell[nr].y);

			    /* Add item to list for cell */
			    if(AddCell(&list, raster, &nrList, inputCell,
				  outputCell, currRow, X, nrMaps,
				   (size_t)c, nrCoverCells, aligned, angle))
				      return 1;
			    Free(inputCell);	/* deallocate */
		 	}
		}
	}	 

	/* calculate output value of pixel according value scale */
	vs = RgetValueScale(in[0]);
	if(vs != VS_DIRECTION)
		CalcScalarOut(out, (size_t)rOut, (size_t)cOut, nrList, list, nrCoverCells, nrMaps);
	else
		CalcDirectionOut(out, (size_t) rOut, (size_t) cOut, nrList, list, nrCoverCells, nrMaps);

	Free(outputCell);		/* deallocate */
	Free(list);			/* deallocate */
	return 0;			/* successfully terminated */
}
Beispiel #5
0
/* Function for resampling  N input maps into 1 output map.
 * Assumes a map "clone.map" and N "input.map"s present. Checks on
 * options for percentage and maximum value. 
 * Determines type and characteristics of output map.
 * Returns nothing, exits with 1 in case of error.
 */
int main(int argc,		/* number of arguments */
	char *argv[])		/* list of arguments */
{
     	MAP 	*clone, *out, *tmp, **in;
     	char 	*outputName, *cloneName;	
     	int 	c, borderval;	
     	size_t  nrMaps,i;
	REAL8 	X0, Y0, cellSize, angleIn, angleOut;
	size_t 	nrRows, nrCols;
	CSF_PT 	projection;
	CSF_CR  cellRepr;
	CSF_VS  valueScale;
	double 	percent = 0, errFactor = 2.5, resampleN = 0.0;
	BOOL	aligned = TRUE;
	BOOL    keepInputMinMax = FALSE;
	REAL8	minAllInput=0, maxAllInput=0;
	BOOL	onlyReal4 = TRUE, contract = FALSE;
	BOOL	onlyUint1 = TRUE;

	if(InstallArgs(argc, argv,"axmp$r$c#b#e$RBCk", "resample", __DATE__))
		exit(1);

     	while((c = GetOpt()) != 0)
     	{
     	    switch(c)
     	    {
     	    	case 'b': opB = TRUE;
     	    		borderval = *((int *) OptArg);
     	    		break;
     	    	case 'B': opB = TRUE;
     	    		borderval = 0;
     	    		break;
     	    	case 'C': opMV = TRUE;
     	    		borderval = 0;
     	    		break;
     	    	case 'c': opMV = TRUE;
     	    		borderval = *((int *) OptArg);
     	    		break;
     	    	case 'a':contract = TRUE;
     	    		break;
     	    	case 'x':contract = FALSE;
     	    		break;
     	    	case 'm':opMax = 1;
     	    		break;
     	    	case 'p':opPer = 1;
     	    		percent = *((double*) OptArg);
     	    		if(percent < 0 || 100 < percent)
     	    		{
     	    			Error("illegal percentage");
     	    			exit(1);
     	    		}
     	    		break;
     	    	case 'R':opR = 1;
     	    		resampleN = 1;
     	    		break;
     	    	case 'r':opR = 1;
     	    		resampleN = *((double*) OptArg);
     	    		break;
     	    	case 'e':optionAcc = 1;
     	    		errFactor = *((double*) OptArg);
     	    		break;
     	    	case 'k': keepInputMinMax = TRUE;
     	    		break;
     	    }
     	}

	argv = ArgArguments(&argc);
	if (AppArgCountCheck(argc,3,-1,USAGE))
		exit(1);

	outputName = argv[argc-1];
  	nrMaps  = argc-2;

	/* Read the desired specifics out of the clone map 
	 * or use first input as clone map
	 */
	cloneName = NO_CLONE_NEEDED ? argv[1] : NULL;
	if ( (clone = AppOpenClone(&cloneName,cloneName)) == NULL)
		exit(1);

	/* Determine the valueScale out of 1st input map */
	tmp = Mopen(argv[1], M_READ);
	if(tmp == NULL)
		MperrorExit(argv[1], 1);

	/* all input maps have same value scale */
	valueScale = RgetValueScale(tmp);
	if(valueScale == VS_LDD && !opMV)
	{
		Error("can not do this type of resampling on map '%s' with type ldd", argv[1]);
		exit(1);
	}
	/* adjust old ones */
	if(valueScale == VS_CLASSIFIED)
		valueScale = VS_ORDINAL;
	if(valueScale == VS_CONTINUOUS)
		valueScale = VS_SCALAR;

	/* get location attributes of clone or of 1st input map */
	projection = MgetProjection(clone);
	nrRows = RgetNrRows(clone);
	nrCols = RgetNrCols(clone);
	X0 = RgetX0(clone);
	Y0 = RgetY0(clone);
	cellRepr = RgetCellRepr(clone);
	angleOut = RgetAngle(clone); 

	/* resample option -> cell size(inputmap) * factor 
	 * Number of rows and columns are divided by resample
	 * factor.
	 */
	if(opR == 1)
	{
		/* setting for unit */
		if(!appUnitTrue)
		{
			cellSize = resampleN;
			resampleN /= (double) RgetCellSize(tmp);
		}
		else
			cellSize = RgetCellSize(tmp) * resampleN;
		if(contract)
		{
			nrRows = floor((double) nrRows / 
					(double) resampleN);
			nrCols = floor((double) nrCols / 
					(double) resampleN);

			/* Prevent an illegal map */
			if(nrRows == 0)
				nrRows = 1;
			if(nrCols == 0)
				nrCols = 1;
		}
		else
		{
			nrRows = ceil((double) nrRows / 
					(double) resampleN);
			nrCols = ceil((double) nrCols / 
					(double) resampleN);
		}
	}
	else
		cellSize = RgetCellSize(clone);

	/* Allocate memory for the input map pointers */
	in = (MAP **)ChkMalloc(sizeof(MAP *) * nrMaps);
	if(in == NULL)
	{
		AppEnd();
		exit(1);
	}

	/* Read all input maps with desired cell representation */
	for(i = 0; i < nrMaps; i++)
	{
		REAL8	tmpMin, tmpMax;

		tmp = Mopen(argv[1 + i], M_READ);
		angleIn = RgetAngle(tmp);
		if(angleIn != 0)
			aligned = FALSE;
		if(tmp == NULL)
			MperrorExit(argv[1 + i], 1);

		if(!RvalueScaleIs(tmp, valueScale))
		{
			Error("%s has illegal data type: '%s'\n",
				argv[1 + i], RstrValueScale(valueScale));
			exit(1);
		}

		in[i] = tmp;

		/* Determine which cell representation should be used */
		onlyReal4 = RgetCellRepr(in[i]) == CR_REAL4;
		onlyUint1 = RgetCellRepr(in[i]) == CR_UINT1;


		RuseAs(in[i], CR_REAL8);
		RgetMinVal(tmp, &tmpMin);
		RgetMaxVal(tmp, &tmpMax);
		if (i==0)
		 {minAllInput = tmpMin; maxAllInput = tmpMax; }
		minAllInput = MIN(minAllInput,tmpMin);
		maxAllInput = MAX(maxAllInput,tmpMax);

		if(AppIsClassified(valueScale))
			RuseAs(in[i], CR_INT4);
		else
			RuseAs(in[i], CR_REAL8);
	}

	if(opB == 1 || opMV == 1)
	{
		if(CheckInputMaps(in, nrMaps, projection, angleIn, cellSize))
		{
			Error("");
			FreeMaps(in, nrMaps);
			exit(1);
		}

		if(opB == 1)
		{
			if(SmallestFittingRectangle(&X0, &Y0, &nrRows,
			  &nrCols, in, borderval, nrMaps,
			  cellSize, angleIn, projection, contract))
			{
				FreeMaps(in, nrMaps);
				AppEnd();
				exit(1);
			}
		}
		else
		{
		  	if(SmallestNonMVRect(&X0, &Y0, &nrRows, &nrCols, in,
		  	borderval, nrMaps, valueScale, cellSize,
		  	angleIn, projection, contract))
			{	
				FreeMaps(in, nrMaps);
				AppEnd();
				exit(1);
			}
		}
	}

	/* Create output map with suitable cell representation */ 
	/* NOTE ! Create map with smallest representation possible */
	out = Rcreate(outputName, nrRows, nrCols, 
	               AppIsClassified(valueScale) ?
		               (onlyUint1 ? CR_UINT1 : CR_INT4) :
		               (onlyReal4 ? CR_REAL4 : CR_REAL8),
		               valueScale, projection, X0, Y0, 
		               angleOut, cellSize);
	if(out == NULL)
	{
		FreeMaps(in, nrMaps);
		Error("can not create output map '%s': %s", 
		      argv[1], MstrError());
		exit(1);
	}
	RuseAs(out, AppIsClassified(valueScale) ? CR_INT4 : CR_REAL8);

	if(angleOut != 0)
		aligned = FALSE;


	/* determine raster size according wanted accuracy */
	if(opB != 1 && opMV != 1)
	{
		if(DetRasterSize(out, in, nrMaps, errFactor))
		{
			Error("Illegal cell size\n");
			exit(1);
		}
	}
	else
		rasterSize = 1;

	if(nrMaps > 1 && percent > 0)
		AppProgress("rasterSize: %d\n", rasterSize);
	else
		AppProgress("No raster used\n");

	/* Call function */
	if(AppIsClassified(valueScale))
	{	/* Call resample function for classified maps */

		if(SampleClass(out, in, percent, nrMaps, nrRows, nrCols,
		   aligned, angleOut))
		{	
			EndResample(in, nrMaps, out);
			exit(1);	/* Memory allocation failed */
		}	
	}		
	else
	{	/* Call resample function for continuous maps */
		if(SampleCont(out, in, percent, nrMaps, nrRows, nrCols,
		   aligned, angleOut))
		{	
			EndResample(in, nrMaps, out);
			exit(1);	/* Memory allocation failed */
		}	
	}		

	/* End of call */
	if (keepInputMinMax) {
		RuseAs(out, CR_REAL8);
		RputMinVal(out, &minAllInput);
		RputMaxVal(out, &maxAllInput);
	}
	EndResample(in, nrMaps, out);
	
	exit(0);  			/* Successful exit */
	return 0; 			/* Never reached */
} /* main */
Beispiel #6
0
/* Determines smallest rectangle around nonMv values.
 * The border value can be added around this rectangle.
 * Returns x0, y0 , nrRows and nrCols for out.
 */
static int SmallestNonMVRect(
	REAL8 *X0out,		/* write-only X0 */
	REAL8 *Y0out,		/* write-only Y0 */
	size_t *nrRows,		/* write-only nr of rows */
	size_t *nrCols,		/* write-only nr of columns */
	MAP **in,  		/* read-only pointer in maps */
	int borderValue,	/* border value */
	size_t nrMaps,		/* number of input maps */
	CSF_VS valueScale,	/* value scale of output map */
	REAL8 cellSize,		/* cellSize of map */
	REAL8 angle,		/* angle of output map */
	CSF_PT projection,	/* projection of output map */
	BOOL contract)		/* map should be contracted */
{
	size_t 	i;
	POINT2D 	leftUpperC, leftLowerC, rightUpperC, rightLowerC;
	REAL8 	upperB=0, leftB=0, rightB=0, belowB=0;
 	   /* ^- shut up about use before def */

	for(i = 0; i < nrMaps; i++)
	{
		MAP	*X = in[i];
		BOOL	first = TRUE;
		POINT2D	polygon[4];
		size_t 	r, c;
		size_t 	nrR = RgetNrRows(X);
		size_t 	nrC = RgetNrCols(X);

		for(r = 0; r < nrR; r++)
		 for(c = 0; c < nrC; c++)
		 {
	 		INT4 int4Val;
	 		REAL8 real8Val;

	 		if((AppIsClassified(valueScale) &&
	 		  RgetCell(in[i], r, c, &int4Val) &&
	 		  int4Val != MV_INT4) ||
	 		  (!AppIsClassified(valueScale) && 
	 		  RgetCell(in[i], r, c, &real8Val) &&
	 		  (IsMV(in[i], &real8Val) == FALSE)))
	 		{
				if(first || c < leftB)
					leftB = c;
				if(first || c > rightB)
					rightB = c;
				if(first || r > belowB)
					belowB = r;
				if(first || r < upperB)
					upperB = r;
				first = FALSE;
			}
		}

		/* Get coordinates of corners */
		RrowCol2Coords(X, upperB, leftB, &polygon[0].x,
			&polygon[0].y);
		RrowCol2Coords(X, upperB, rightB + 1 - EPSILON,
			&polygon[1].x, &polygon[1].y);
		RrowCol2Coords(X, belowB + 1 - EPSILON, leftB,
			&polygon[2].x, &polygon[2].y);
		RrowCol2Coords(X, belowB + 1 - EPSILON,
		    rightB + 1 - EPSILON, &polygon[3].x, &polygon[3].y);

		/* Rotate all corners of map */	
		if(angle != 0)
		{
			for(c = 0; c < 4; c++)
		   	    polygon[c] = *RotPoint(polygon + c, angle);
		}

		/* Determine boundaries of rotated output map */
		for(c = 0; c < 4; c++)
		{
			if(polygon[c].y > belowB || (i == 0 && c == 0))
				belowB = polygon[c].y;
			if(polygon[c].y < upperB || (i == 0 && c == 0))
				upperB = polygon[c].y;
			if(polygon[c].x > rightB || (i == 0 && c == 0))
				rightB = polygon[c].x;
			if(polygon[c].x < leftB || (i == 0 && c == 0))
				leftB = polygon[c].x;
		}
	}

	leftUpperC.x = leftB;
	rightUpperC.x = rightB;
	leftLowerC.x = leftB;
	rightLowerC.x = rightB;

	if(projection == PT_YINCT2B)
	{
		leftUpperC.y = upperB;
		rightUpperC.y = upperB;
		leftLowerC.y = belowB;
		rightLowerC.y = belowB;
	}
	else
	{
		leftUpperC.y = belowB;
		rightUpperC.y = belowB;
		leftLowerC.y = upperB;
		rightLowerC.y = upperB;
	}

	CalcBound(X0out, Y0out, nrRows, nrCols, &leftUpperC, &rightUpperC,
	 	&leftLowerC, &rightLowerC, borderValue, cellSize, angle,
	 	projection, contract);
	return 0;
}
Beispiel #7
0
/* Determines the smallest fitting rectangle around input maps. 
 * The bordervalue is added.
 * Returns x0, y0, nrRows and nrCols for out.
 */
static int SmallestFittingRectangle(
	REAL8 *X0out,		/* write-only X0 */
	REAL8 *Y0out,		/* write-only Y0 */
	size_t *nrRows,		/* write-only nr of rows */
	size_t *nrCols,		/* write-only nr of columns */
	MAP **in,  		/* read-only pointer to input maps */
	int borderValue,	/* bordervalue */
	size_t nrMaps,		/* number of input maps */
	REAL8 cellSize,		/* cell size of output map */
	REAL8 angle,		/* angle of output map */
	CSF_PT projection,	/* projection of output map */
	BOOL contract)		/* map should be contracted */
{
	size_t	i;
	REAL8	upperB=0, leftB=0, rightB=0, belowB=0;
	   /* ^- shut up about use before def */
	POINT2D	leftUpperC, rightUpperC, leftLowerC, rightLowerC;

	/* determine the boundaries for every map */
	for(i = 0; i < nrMaps; i++)
	{
		MAP	*X = in[i];
		int	c;
		POINT2D	polygon[4];		/* rectangle */
		REAL8	X0 = RgetX0(X);
		REAL8	Y0 = RgetY0(X);
		REAL8	nrR = (REAL8) RgetNrRows(X);
		REAL8	nrC = (REAL8) RgetNrCols(X);

		/* transform corners of map into x- and y-coordinates */
		polygon[0].x = X0;
		polygon[0].y = Y0;
		RrowCol2Coords(X, 0.0, nrC - EPSILON, &polygon[1].x,
				&polygon[1].y);
		RrowCol2Coords(X, nrR - EPSILON, nrC - EPSILON,
				&polygon[2].x, &polygon[2].y);
		RrowCol2Coords(X, nrR - EPSILON, 0.0, &polygon[3].x,
			&polygon[3].y);

		/* Rotate all corners of map */	
		if(angle != 0)
			for(c = 0; c < 4; c++)
			    RotPoint(polygon + c, angle);

		/* Determine boundaries of rotated output map */
		for(c = 0; c < 4; c++)
		{
			if((i==0&&c==0)||polygon[c].y > belowB)
				belowB = polygon[c].y;
			if((i==0&&c==0)||polygon[c].y < upperB)
				upperB = polygon[c].y;
			if((i==0&&c==0)||polygon[c].x > rightB)
				rightB = polygon[c].x;
			if((i==0&&c==0)||polygon[c].x < leftB)
				leftB = polygon[c].x;
		}
	}

	/* Put boundaries in corners of the rotated map */
	leftUpperC.x = leftB;
	rightUpperC.x = rightB;
	leftLowerC.x = leftB;
	rightLowerC.x = rightB;

	if(projection == PT_YINCT2B)
	{
		leftUpperC.y = upperB;
		rightUpperC.y = upperB;
		leftLowerC.y = belowB;
		rightLowerC.y = belowB;
	}
	else
	{
		leftUpperC.y = belowB;
		rightUpperC.y = belowB;
		leftLowerC.y = upperB;
		rightLowerC.y = upperB;
	}

	/* calculate the boundary of the output map */
	CalcBound(X0out, Y0out, nrRows, nrCols, &leftUpperC, &rightUpperC,
	 	&leftLowerC, &rightLowerC, borderValue, cellSize, angle,
	 	projection, contract);
	return 0;
}