/* test value scale on compatibility CSF version 1 and 2 * RvalueScaleIs tests if the map's value scale is compatible * with a certain value scale. Here is list of compatible but * different value scales: * * VS_NOTDETERMINED: always returns 0 * * VS_CLASSIFIED: VS_NOTDETERMINED * * VS_CONTINUOUS: VS_NOTDETERMINED * * VS_BOOLEAN: VS_CLASSIFIED, VS_NOTDETERMINED * * VS_NOMINAL: VS_CLASSIFIED, VS_NOTDETERMINED * * VS_ORDINAL: VS_CLASSIFIED, VS_NOTDETERMINED * * VS_LDD: VS_CLASSIFIED, VS_NOTDETERMINED (only if cell representation is * UINT1 or INT2) * * VS_SCALAR: VS_CONTINUOUS, VS_NOTDETERMINED * * VS_DIRECTION: none * * returns * 0 if not compatible or if vs argument is VS_NOTDETERMINED or in case of * error, nonzero if * compatible. * * Merrno * BAD_VALUESCALE * * EXAMPLE * .so examples/maskdump.tr */ int RvalueScaleIs( const MAP *m, /* a version 1 map handle */ CSF_VS vs) /* a version 2 value scale that is compatible with map's value * scale yes or no? */ { CSF_VS mapsVS = RgetValueScale(m); if (vs == VS_NOTDETERMINED) return 0; if (vs == mapsVS) return 1; switch(vs) { case VS_CLASSIFIED: return mapsVS == VS_NOTDETERMINED; case VS_CONTINUOUS: return mapsVS == VS_NOTDETERMINED; case VS_LDD: { CSF_CR cr = RgetCellRepr(m); if (cr != CR_UINT1 && cr != CR_INT2) return 0; } /* fall through */ case VS_BOOLEAN: case VS_NOMINAL: case VS_ORDINAL: return mapsVS == VS_CLASSIFIED || mapsVS == VS_NOTDETERMINED; case VS_SCALAR: return mapsVS == VS_CONTINUOUS || mapsVS == VS_NOTDETERMINED; /* direction isn't compatible with anything */ case VS_DIRECTION: return 0; default : M_ERROR(BAD_VALUESCALE); return 0; } }
/* read a stream of cells * RgetSomeCells views a raster as one linear stream of * cells, with row i+1 placed after row i. * In this stream any sequence can be read by specifying an * offset and the number of cells to be read * returns the number of cells read, just as fread * * example * .so examples/somecell.tr */ size_t RgetSomeCells( MAP *map, /* map handle */ size_t offset, /* offset from pixel (row,col) = (0,0) */ size_t nrCells, /* number of cells to be read */ void *buf)/* write-only. Buffer large enough to * hold nrCells cells in the in-file cell representation * or the in-app cell representation. */ { CSF_FADDR readAt; size_t cellsRead; UINT2 inFileCR = RgetCellRepr(map); offset <<= LOG_CELLSIZE(inFileCR); readAt = ADDR_DATA + (CSF_FADDR)offset; fseek(map->fp, (long)readAt, SEEK_SET); cellsRead = map->read(buf, (size_t)CELLSIZE(inFileCR), (size_t)nrCells, map->fp); PRECOND(map->file2app != NULL); map->file2app(nrCells, buf); return(cellsRead); }
/* allocate dynamic memory large enough to hold in-file and app cells * Rmalloc allocates memory to hold nrOfCells * cells in both the in-file and app cell representation. Allocation * is done by malloc for other users. Our own (utrecht university) applications * calls ChkMalloc. Freeing memory allocated by Rmalloc is done by free (or Free). * * NOTE * Note that a possible RuseAs call must be done BEFORE Rmalloc. * * returns * a pointer the allocated memory or * NULL * if the request fails * * example * .so examples/_row.tr */ void *Rmalloc( const MAP *m, /* map handle */ size_t nrOfCells) /* number of cells allocated memory must hold */ { CSF_CR inFileCR = RgetCellRepr(m); CSF_CR largestCellRepr = LOG_CELLSIZE(m->appCR) > LOG_CELLSIZE(inFileCR) ? m->appCR : inFileCR; return CSF_MALLOC((size_t)CSFSIZEOF(nrOfCells, largestCellRepr)); }
/* 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); }
void RputMinVal( MAP *map, /* map handle */ const void *minVal) /* New minimum value */ { /* use buffer that can hold largest * cell representation */ CSF_VAR_TYPE buf_1; void *buf = (void *)(&buf_1); CHECKHANDLE(map); /* make a copy */ CsfGetVarType(buf, minVal, map->appCR); /* convert */ map->app2file(1, buf); /* set */ CsfGetVarType( (void *)&(map->raster.minVal), buf, RgetCellRepr(map)); map->minMaxStatus = MM_DONTKEEPTRACK; }
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; }
int RuseAs( MAP *m, /* map handle */ CSF_CR useType) /* CR_UINT1,CR_INT4, CR_REAL4, CR_REAL8, VS_BOOLEAN or VS_LDD */ { CSF_CR inFileCR = RgetCellRepr(m); CSF_VS inFileVS = RgetValueScale(m); int hasInFileCellReprType2 = HasInFileCellReprType2(inFileCR); /* it is very unconvenient that both, VS and CR are taken as arguments * for this function, and previously were used in the switch statement * now, at least 'special conversions' handled first */ if((int)useType == VS_BOOLEAN){ switch(inFileVS) { case VS_LDD: case VS_DIRECTION: { M_ERROR(CANT_USE_AS_BOOLEAN); return 1; } case VS_BOOLEAN: { POSTCOND(inFileCR == CR_UINT1); m->appCR = CR_UINT1; m->file2app = same; m->app2file = same; return 0; } default: { if((!hasInFileCellReprType2) && WRITE_ENABLE(m)) { /* cellrepr is old one, we can't write that */ M_ERROR(CANT_USE_WRITE_BOOLEAN); return 1; } m->appCR = CR_UINT1; m->file2app = ConvFuncBool(inFileCR); m->app2file = ConvFunc(inFileCR, CR_UINT1); return 0; } } } else if ((int)useType == VS_LDD){ switch(inFileVS) { case VS_LDD: { POSTCOND(inFileCR == CR_UINT1); m->appCR = CR_UINT1; m->file2app = same; m->app2file = same; return 0; } case VS_CLASSIFIED: case VS_NOTDETERMINED: { switch(inFileCR) { case CR_UINT1: { m->appCR = CR_UINT1; m->file2app = UINT1tLdd; m->app2file = same; return 0; } case CR_INT2: { if(WRITE_ENABLE(m)) { M_ERROR(CANT_USE_WRITE_LDD); return 1; } m->appCR = CR_UINT1; m->file2app = INT2tLdd; m->app2file = illegal; return 0; } default: { /* This should never happen. * Shut up compiler. */ assert(0); } } } default: { M_ERROR(CANT_USE_AS_LDD); return 1; } } } switch(useType) { case CR_UINT1: case CR_INT4 : case CR_REAL4: case CR_REAL8: { if((!hasInFileCellReprType2) && WRITE_ENABLE(m)) { /* cellrepr is old one, we can't write that */ M_ERROR(CANT_USE_WRITE_OLDCR); return 1; } m->appCR = useType; m->file2app = ConvFunc(useType, inFileCR); m->app2file = ConvFunc(inFileCR, useType); POSTCOND(m->file2app != NULL); return 0; } default: { M_ERROR(ILLEGAL_USE_TYPE); return 1; } } /* NOTREACHED */ }
int main(int argc, char *argv[]) { MAP *out, *clone = NULL; int c; size_t colNr[3] = {0 /*X*/, 1 /*Y*/, 2 /*V*/}; /* internal indices */ const char *mv = "1e31"; char *cloneFileName; COMP_CELL compCell = NOTHING; CSF_CR cellRepr; CSF_VS valueScale = VS_UNDEFINED; int parseVal; int sepChar = ','; if (InstallArgs(argc, argv, "x#y#v#m*(BLNOSDV)(atHM)(hl)s*", "col2map", __DATE__)) goto failure; while ((c = GetOpt()) != 0) switch (c) { case 'x': parseVal = (*((const int *)OptArg)) - 1; if (parseVal < 0) { Error("-x: x column should be greater than 0"); goto failure; } colNr[POS_X] = (size_t)parseVal; break; case 'y': parseVal = (*((const int *)OptArg)) - 1; if (parseVal < 0) { Error("-y: y column should be greater than 0"); goto failure; } colNr[POS_Y] = (size_t)parseVal; break; case 'v': parseVal = (*((const int *)OptArg)) - 1; if (parseVal < 0) { Error("-v: value column should be greater than 0"); goto failure; } colNr[POS_V] = (size_t)parseVal; break; case 'm': mv = (const char *)OptArg; break; case 'a': compCell = AVERAGE; break; case 'H': compCell = HIGHEST; break; case 'h': compCell = MAJORITY; break; case 'M': compCell = LOWEST; break; case 'l': compCell = MINORITY; break; case 't': compCell = TOTAL; break; case 's': sepChar = ((const char *)OptArg)[0]; if (isdigit(sepChar)) { Error("-s: separator must be a non-digit (not [0-9])"); goto failure; } break; #include "case_vs.h" } argv = ArgArguments(&argc); if (argv == NULL) goto failure; if (AppArgCountCheck(argc, 3, 3, USAGE)) goto failure; if (AppInputTest(argv[1])) goto failure; /* open the clone map */ clone = AppOpenClone(&cloneFileName, NULL); if (clone == NULL) goto failure; if (valueScale == VS_UNDEFINED) { valueScale = RgetValueScale(clone); cellRepr = RgetCellRepr(clone); } else cellRepr = AppDefaultCellRepr(valueScale); if (!RvalueScale2(valueScale)) { Error("clone map '%s' has an illegal value scale", cloneFileName); goto failure2; } if (compCell == NOTHING) { /* defaults */ switch (valueScale) { case VS_SCALAR: compCell = AVERAGE; break; case VS_DIRECTION: compCell = DIR_AVERAGE; break; default: compCell = MAJORITY; break; } } else { BOOL conflict = FALSE; CSF_VS vs = valueScale; switch (compCell) { case AVERAGE: conflict = (vs != VS_SCALAR && vs != VS_DIRECTION); if (vs == VS_DIRECTION) compCell = DIR_AVERAGE; break; case LOWEST: case HIGHEST: conflict = (vs != VS_SCALAR && vs != VS_ORDINAL); break; case MAJORITY: case MINORITY: conflict = (vs == VS_SCALAR || vs == VS_DIRECTION); break; case TOTAL: conflict = vs != VS_SCALAR; break; default: POSTCOND(FALSE); } if (conflict) { CompCellError(compCell, vs); goto failure2; } } out = Rdup(argv[2], clone, cellRepr, valueScale); if (out == NULL) { Error("output map '%s' can not be created", argv[2]); goto failure2; } Mclose(clone); clone = NULL; RuseAs(out, CR_REAL8); if (Col2Map(out, argv[1], compCell, mv, colNr, sepChar)) { Mclose(out); (void)remove(argv[2]); goto failure; } Mclose(out); AppEnd(); exit(0); return 0; failure2: if (clone == NULL) Mclose(clone); failure: AppEnd(); exit(1); return 1; } /* main */
/* seek to space for attribute (LIBRARY_INTERNAL) * CsfSeekAttrSpace seeks to the a point in the file where * the attribute must be stored and update the attribute control * blocks accordingly. * Writing can still fail since there is no check if that space is really * avalaible on the device. After this call returns the file is already * seeked to the point the functions returns. * returns the file position or 0 in case of error. * * Merrno * ATTRDUPL * NOACCESS * WRITE_ERROR */ CSF_FADDR32 CsfSeekAttrSpace( MAP *m, /* map handle */ CSF_ATTR_ID id, /* attribute identification only for check if avalaible */ size_t size) /* size to be seeked to */ { ATTR_CNTRL_BLOCK b; CSF_FADDR32 currBlockPos, prevBlockPos=USED_UNINIT_ZERO, newPos, endBlock, resultPos=0; int noPosFound; int i; if (MattributeAvail(m ,id)) { M_ERROR(ATTRDUPL); goto error; } if (! WRITE_ENABLE(m)) { M_ERROR(NOACCESS); goto error; } currBlockPos = m->main.attrTable; noPosFound = 1; while (noPosFound) { if (currBlockPos == 0) { if (m->main.attrTable == 0) { /* FIRST BLOCK */ newPos =( (CSF_FADDR)(m->raster.nrRows)* (CSF_FADDR)(m->raster.nrCols)* (CSF_FADDR)(CELLSIZE(RgetCellRepr(m)))) + ADDR_DATA; m->main.attrTable = newPos; } else { /* NEW/NEXT BLOCK */ newPos = b.attrs[LAST_ATTR_IN_BLOCK].attrOffset + b.attrs[LAST_ATTR_IN_BLOCK].attrSize; b.next = newPos; if (CsfWriteAttrBlock(m, prevBlockPos, &b)) { M_ERROR(WRITE_ERROR); resultPos = 0; } } InitBlock(&b); b.attrs[0].attrOffset = newPos + SIZE_OF_ATTR_CNTRL_BLOCK; currBlockPos = newPos; noPosFound = 0; } else CsfReadAttrBlock(m, currBlockPos, &b); i = 0; /* this is also the right index if a new block is added ! */ while (noPosFound && i < NR_ATTR_IN_BLOCK) switch (b.attrs[i].attrId) { case END_OF_ATTRS: POSTCOND(i >= 1); /* i >= 1 , no block otherwise */ b.attrs[i].attrOffset = b.attrs[i-1].attrOffset + b.attrs[i-1].attrSize; noPosFound = 0; break; case ATTR_NOT_USED: if (i == NR_ATTR_IN_BLOCK) endBlock = b.next; else endBlock = b.attrs[i+1].attrOffset; if ( (size_t)( endBlock - b.attrs[i].attrOffset) >= size) /* this position can hold the attr */ noPosFound = 0; else i++; break; default: i++; } /* switch */ /* if (b.next == 0) ? When did I change this CW remember this block position since it may be have to rewritten */ prevBlockPos = currBlockPos; if (noPosFound) currBlockPos = b.next; } /* while */ b.attrs[i].attrSize = size; b.attrs[i].attrId = id; resultPos = b.attrs[i].attrOffset; if (CsfWriteAttrBlock(m, currBlockPos, &b)) { M_ERROR(WRITE_ERROR); resultPos = 0; } fseek(m->fp, (long)resultPos, SEEK_SET); /* fsetpos() is better */ error: return resultPos; } /* CsfSeekAttrSpace */
/* 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 */