/*! \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()); }
/* 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); }
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; }
/* 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 */ }
/* 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 */
/* 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; }
/* 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; }