static void ConvertToREAL4( size_t nrCells, void *buf, CSF_CR src) { size_t i; i = (size_t)nrCells; if (IS_SIGNED(src)) { POSTCOND(src == CR_INT4); INT4tREAL4(nrCells, buf); } else { POSTCOND(src == CR_UINT4); { do { i--; if ( ((UINT4 *)buf)[i] == MV_UINT4 ) ((UINT4 *)buf)[i] = MV_UINT4; else ((REAL4 *)buf)[i] = (REAL4)((UINT4 *)buf)[i]; } while(i != 0); } } }
static int BuildEllipse2(REAL8 xmajor_a, REAL8 yminor_b, REAL8 angle) { int i,nrLines,xCeil; int lineStart,lineEndIncl; REAL8 xIncr,c=cos(angle),s=sin(angle); HOR_CUT_LINE *l; PRECOND(xmajor_a != 0); PRECOND(yminor_b != 0); xmajor_a /= Side(); yminor_b /= Side(); xCeil = (size_t)ceil(xmajor_a); nrLines = (xCeil*2)+1; l = (HOR_CUT_LINE *)ChkMalloc(sizeof(HOR_CUT_LINE)*nrLines); for(i=0; i < nrLines; i++) { /* mark not initialized */ SET_MV_REAL4(&(l[i].start.f)); } for (xIncr = 0; xIncr < xCeil; xIncr+=1) { REAL8 y = sqrt( fabs(1-(sqr(xIncr)/sqr(xmajor_a)))*sqr(yminor_b)); Add2Lines(l,nrLines,xCeil,c,s, xIncr, y); Add2Lines(l,nrLines,xCeil,c,s, xIncr,-y); Add2Lines(l,nrLines,xCeil,c,s,-xIncr, y); Add2Lines(l,nrLines,xCeil,c,s,-xIncr,-y); } if (0) { REAL8 y; xIncr = xmajor_a; y = sqrt( fabs(1-(sqr(xIncr)/sqr(xmajor_a)))*sqr(yminor_b)); Add2Lines(l,nrLines,xCeil,c,s, xIncr, y); Add2Lines(l,nrLines,xCeil,c,s, xIncr,-y); Add2Lines(l,nrLines,xCeil,c,s,-xIncr, y); Add2Lines(l,nrLines,xCeil,c,s,-xIncr,-y); } for(i=0; i < nrLines; i++) { /* mark not initialized */ if (!IS_MV_REAL4(&(l[i].start.f))) break; } POSTCOND(i < nrLines); lineStart = i; for(i = nrLines-1; i >=0;i--) { /* mark not initialized */ if (!IS_MV_REAL4(&(l[i].start.f))) break; } POSTCOND(i >= 0); lineEndIncl = i; for (i=lineStart ; i <= lineEndIncl; i++) { PRECOND(!IS_MV_REAL4(&(l[i].start.f))); l[i].start.i = (int)Rint(l[i].start.f); l[i].end.i = (int)Rint(l[i].end.f); } return 1; }
static void ConvertToINT4( size_t nrCells, void *buf, CSF_CR src) { if (IS_SIGNED(src)) { POSTCOND(src == CR_INT2); CONV_SMALL_TO_BIG(nrCells,buf, INT4, INT2); } else { POSTCOND(src == CR_UINT2); CONV_SMALL_TO_BIG(nrCells,buf, INT4, UINT2); } }
int tree_add_right(tree* my_tree, tree* adding) { assert(my_tree != NULL); assert(adding != NULL); PRECOND(tree_check(my_tree -> head -> root, NULL) != TREE_CHECK_OK, TREE_BAD, "ADD LEFT ERROR: PRECONDITION FAILED\n"); int tr_counter = 0; VERIFY1(tree_check(my_tree, &tr_counter) == TREE_CHECK_BAD, TREE_INJURED, "# ADD RIGHT ERROR: [%08x] element, tree is broken\n", my_tree); tr_counter = 0; VERIFY1(tree_check(adding, &tr_counter) == TREE_CHECK_BAD, TREE_ADD_INJURED,"# ADD RIGHT ERROR: [%08x] adding element, tree is broken\n", adding); if (my_tree -> right != NULL) return TREE_ALREADY_THERE; my_tree -> right = adding; if (adding -> papa != NULL) { if (adding -> papa -> left == adding) adding -> papa -> left = NULL; if (adding -> papa -> right == adding) adding -> papa -> right = NULL; } adding -> papa = my_tree; adding -> head = my_tree -> head; adding -> head -> size += tr_counter; assert(my_tree -> head); tree_save_head(adding, my_tree -> head); POSTCOND(tree_check(my_tree -> head -> root, NULL) != TREE_CHECK_OK, TREE_BAD, "ADD LEFT ERROR: POSTCONDITION FAILED\n"); return TREE_OK; }
static void Transform2( size_t nrCells, void *buf, CSF_CR destCellRepr, /* the output representation */ CSF_CR currCellRepr) /* at start of while this is the representation read in the MAP-file */ { /* subsequent looping changes the to the new * converted type */ while(currCellRepr != destCellRepr) { switch(currCellRepr) { case CR_INT1: ConvertToINT2(nrCells, buf, currCellRepr); currCellRepr = CR_INT2; break; case CR_INT2: ConvertToINT4(nrCells, buf, currCellRepr); currCellRepr = CR_INT4; break; case CR_INT4: ConvertToREAL4(nrCells, buf, currCellRepr); currCellRepr = CR_REAL4; break; case CR_UINT1: if (IS_SIGNED(destCellRepr)) { ConvertToINT2(nrCells, buf, currCellRepr); currCellRepr = CR_INT2; } else { UINT1tUINT2(nrCells, buf); currCellRepr = CR_UINT2; } break; case CR_UINT2: if (destCellRepr == CR_INT4) { ConvertToINT4(nrCells, buf, currCellRepr); currCellRepr = CR_INT4; } else { UINT2tUINT4(nrCells, buf); currCellRepr = CR_UINT4; } break; case CR_UINT4: ConvertToREAL4(nrCells, buf, currCellRepr); currCellRepr = CR_REAL4; break; default : POSTCOND(currCellRepr == CR_REAL4); REAL4tREAL8(nrCells, buf); currCellRepr = CR_REAL8; } } }
/* Drains down from each nonzero point. * If one of the neighbors has a MV it will get a MV as output as well. * All of the lowest neighbors get an extra input from current cell. * Returns 1 if memory allocation fails, 0 otherwise. */ static REAL8 DoDrain( MAP_REAL8 *out, /* read-write output map */ const MAP_REAL8 *dem, /* dem map */ const MAP_REAL8 *points, /* points map */ int r, /* current cell row number */ int c) /* current cell column nr. */ { NODE *list = NULL; REAL8 pntVal; /* value in points.map */ REAL8 drainVal; /* total value to drain down */ PRECOND(points->Get(&pntVal, r, c, points)); points->Get(&pntVal, r, c, points); list = LinkChkReal(list, r, c, pntVal); while(list != NULL) { int rowNr = list->rowNr; int colNr = list->colNr; drainVal = list->val.Real; list = RemFromList(list); if(HasLowerNeighbor(dem, points, rowNr, colNr)) { list = DoNeighbors(out, list, dem, points, rowNr, colNr, drainVal); if(list == NULL) return 1; } } POSTCOND(list == NULL); return 0; }
/* vfprintf-flavour of ErrorNested() * See ErrorNested() for full documentation. */ void vfErrorNested( const char *fmt, /* Format control, see printf() for a description */ va_list marker ) /* Optional arguments */ { char *buf; PRECOND (errorNestLevel < 15); if (!errorNestLevel) { /* reset bufs */ errorBuf[0] = '\0'; ptrs[errorNestLevel] = errorBuf; } buf = ptrs[errorNestLevel]; /* print message in buf */ (void)vsprintf(buf, fmt, marker ); /* remove leading and trailing space and newlines */ (void)LeftRightTrim(buf); ptrs[errorNestLevel+1] = ptrs[errorNestLevel]+strlen(buf)+1; errorNestLevel++; POSTCOND(ptrs[errorNestLevel] < errorBuf+BUF_SIZE); }
/* insert a record in a sorted array with unique ids * InsertSorted copies key to the appropriate place, moving * other elements if necessary. Therefore the array must * have space for one more element. NOTE that no records, * including the key (the new one), * must be equal (all unique id's) * returns the copied record (part of array) */ static void *InsertSorted( const void *key, /* key to be inserted */ void *base, /* array of num+1 elements * with element num being vacant */ size_t num, /* number of elements initially in * base */ size_t width, /* sizeof element */ QSORT_CMP cmp)/* comparisson function */ { int x=0; /* num == 0 case */ int c,l=0; int r=num-1; if (num == 0) goto done; do { x = (l+r)/2; if ( (c = cmp(key, ((char *)base)+(x*width))) < 0) r = x-1; else l = x+1; } while (( c != 0) && l <= r ); POSTCOND(c != 0); /* NOT FOUND */ if (c > 0) x++; /* insertion point is after x */ PRECOND(x <= (int)num); if (x != (int)num) /* no memmove if insertion point is at end */ /* move part of array after insertion point 1 to the right */ (void)memmove( (((char *)base)+((x+1)*width)), (((char *)base)+(x*width)), (num-x)*width ); done: return memcpy((((char *)base)+(x*width)), key, width); }
/* set a memory location to a missing value * SetMVcellRepr sets a memory location to a missing value * (using the application cell representation). * In general one should use assignment for * integers (e.g. v = MV_UINT1) or the macro's * SET_MV_REAL4 and SET_MV_REAL8 * */ void SetMVcellRepr( CSF_CR cellRepr, /* cell representation, one of the CR_* constants */ void *c) /* write-only. location set to missing value */ { switch (cellRepr) { case CR_INT1 : *((INT1 *)c) = MV_INT1; break; case CR_INT2 : *((INT2 *)c) = MV_INT2; break; case CR_INT4 : *((INT4 *)c) = MV_INT4; break; case CR_UINT1 : *((UINT1 *)c) = MV_UINT1; break; case CR_UINT2 : *((UINT2 *)c) = MV_UINT2; break; case CR_REAL8 : ((UINT4 *)c)[1] = MV_UINT4; default : POSTCOND( cellRepr == CR_REAL8 || cellRepr == CR_REAL4 || cellRepr == CR_UINT4 ); *((UINT4 *)c) = MV_UINT4; } }
static int BuildCircle(REAL8 radius) { int i,nrLines,xFloor; REAL8 xIncr,lineStart,lineEndIncl; HOR_CUT_LINE *l; PRECOND(radius != 0); radius /= (Side()*2); xFloor = (size_t)floor(radius); radius *= radius; nrLines = (xFloor*2)+1; l = (HOR_CUT_LINE *)ChkMalloc(sizeof(HOR_CUT_LINE)*nrLines); for(i=0; i < nrLines; i++) { /* mark not initialized */ SET_MV_REAL4(&(l[i].start.f)); } for (xIncr = 0; xIncr <= xFloor; xIncr+=1) { REAL8 y = floor(sqrt(radius-sqr(xIncr))); Add2Lines(l,nrLines,xFloor,1,0, xIncr, y); Add2Lines(l,nrLines,xFloor,1,0, xIncr,-y); Add2Lines(l,nrLines,xFloor,1,0,-xIncr, y); Add2Lines(l,nrLines,xFloor,1,0,-xIncr,-y); } for(i=0; i < nrLines; i++) { /* mark not initialized */ if (!IS_MV_REAL4(&(l[i].start.f))) break; } POSTCOND(i < nrLines); lineStart = i; for(i = nrLines-1; i >=0;i--) { /* mark not initialized */ if (!IS_MV_REAL4(&(l[i].start.f))) break; } POSTCOND(i >= 0); lineEndIncl = i; for (i=(int)lineStart ; i <= (int)lineEndIncl; i++) { PRECOND(!IS_MV_REAL4(&(l[i].start.f))); l[i].start.i = (int)Rint(l[i].start.f); l[i].end.i = (int)Rint(l[i].end.f); } return 1; }
/* remove map from run time structure (LIBRARY_INTERNAL) * The map handle will become invalid. */ void CsfUnloadMap( MAP *m) /* map handle */ { POSTCOND(CsfIsValidMap(m)); mapList[m->mapListId] = NULL; m->mapListId = -1; }
int tree_burn(tree* my_tree, int type, ...) { PRECOND(my_tree == NULL, TREE_ARG_TREE_NULL, "TREE INIT: argumented head pointer is NULL\n"); //PRECOND((my_tree -> type != TR_NONE)||(my_tree -> value != NULL), TREE_BAD, "TREE UNIT: tree has been already initialized"); int _size = 0; VERIFY(tree_check(my_tree, &_size) != TREE_CHECK_OK, TREE_BAD, "TREE INIT: Initialization failed, tree is not ok"); va_list vl; va_start(vl, type); char* str = NULL; double val = 0; int int_val = 0; if (my_tree -> value) { DBG_FREE fprintf(stdout, "[%08x] tree.cpp, tree_burn, my_tree -> value\n", my_tree -> value); free(my_tree -> value); my_tree -> value = NULL; } switch (type) { case TR_V: case TR_STR: case TR_F: str = va_arg(vl, char*); VERIFY(strlen(str) >= MAXLINE, TREE_BAD, "TREE INIT: Argumented string is out of range"); my_tree -> value = (void*)calloc(strlen(str) + 2, sizeof(char)); assert(my_tree -> value); strcpy((char*)(my_tree -> value), str); break; case TR_N: val = va_arg(vl, double); my_tree -> value = (void*) calloc(1, sizeof(double)); assert(my_tree -> value); *((double*)(my_tree -> value)) = val; break; case TR_SIGN: case TR_ASSN: case TR_CMP: int_val = va_arg(vl, int); my_tree -> value = (void*) calloc(1, sizeof(int)); assert(my_tree -> value); *((int*)(my_tree -> value)) = int_val; break; default: break; } my_tree -> type = type; _size = 0; va_end(vl); POSTCOND(tree_check(my_tree, &_size) != TREE_CHECK_OK, TREE_BAD, "TREE INIT: Initialization failed, tree is not ok in the end"); return TREE_OK; }
/* boot the CSF runtime library (LIBRARY_INTERNAL) * CsfBootCsfKernel creates the mapList and adds the function to * close all files at a system exit * * NOTE * Note that CsfBootCsfKernel never returns if there isn't enough * memory to allocate an array of mapListLen pointers, or if * the atexit() call fails */ void CsfBootCsfKernel(void) { POSTCOND(mapList == NULL); mapList = (MAP **)calloc(mapListLen,sizeof(MAP *)); if (mapList == NULL) { (void)fprintf(stderr,"CSF_INTERNAL_ERROR: Not enough memory to use CSF-files\n"); exit(1); } if (atexit(CsfCloseCsfKernel)) { (void)fprintf(stderr,"CSF_INTERNAL_ERROR: Impossible to close CSF-files automatically at exit\n"); exit(1); } }
/* read an attribute (LIBRARY_INTERNAL) * MgetAttribute reads an attribute if it is available. * Be aware that you can't pass a simple pointer to some * (array of) structure(s) due to alignment en endian problems. * At some time there will be a separate get function for each attribute * returns 0 if the attribute is not found, arg id if * the attribute is found. */ CSF_ATTR_ID CsfGetAttribute( MAP *m, /* map handle */ CSF_ATTR_ID id, /* id of attribute to be read */ size_t elSize, /* size of each data-element */ size_t *nmemb, /* write-only. How many elSize members are read. */ void *attr) /* write-only. buffer where attribute is read in. * Must be big enough to hold buffer. */ { ATTR_CNTRL_BLOCK b; CSF_FADDR pos; PRECOND(CsfValidSize(elSize)); CHECKHANDLE_GOTO(m, error); if (! READ_ENABLE(m)) { M_ERROR(NOACCESS); goto error; } if (CsfGetAttrBlock(m, id, &b) != 0) { int i = CsfGetAttrIndex(id, &b); *nmemb = b.attrs[i].attrSize; POSTCOND( ((*nmemb) % elSize) == 0); *nmemb /= elSize; POSTCOND( (*nmemb) > 0); pos = b.attrs[i].attrOffset; (void)fseek(m->fp, (long)pos, SEEK_SET); m->read(attr,elSize, (size_t)(*nmemb),m->fp); return(id); } else *nmemb = 0; error: return(0); /* not available or an error */ } /* MgetAttribute */
/* compute (xUL,yUL) and nrRows, nrCols from some coordinates * RcomputeExtend computes parameters to create a raster maps * from minimum and maximum x and y coordinates, projection information, * cellsize and units. The resulting parameters are computed that the * smallest raster map can be created that will include the two * coordinates given, assuming a default angle of 0. * Which coordinates are the maximum or minimum are * determined by the function itself. */ void RcomputeExtend( REAL8 *xUL, /* write-only, resulting xUL */ REAL8 *yUL, /* write-only, resulting yUL */ size_t *nrRows, /* write-only, resulting nrRows */ size_t *nrCols, /* write-only, resulting nrCols */ double x_1, /* first x-coordinate */ double y_1, /* first y-coordinate */ double x_2, /* second x-coordinate */ double y_2, /* second y-coordinate */ CSF_PT projection, /* required projection */ REAL8 cellSize, /* required cellsize, > 0 */ double rounding) /* assure that (xUL/rounding), (yUL/rouding) * (xLL/rounding) and (yLL/rounding) will * will all be an integers values > 0 */ { /* * xUL ______ | | | | | | ------ */ double yLL,xUR = x_1 > x_2 ? x_1 : x_2; *xUL = x_1 < x_2 ? x_1 : x_2; *xUL = RoundDown(*xUL, rounding); /* Round down */ xUR = RoundUp( xUR, rounding); /* Round up */ POSTCOND(*xUL <= xUR); *nrCols = (size_t)ceil((xUR - *xUL)/cellSize); if (projection == PT_YINCT2B) { yLL = y_1 > y_2 ? y_1 : y_2; /* highest value at bottom */ *yUL = y_1 < y_2 ? y_1 : y_2; /* lowest value at top */ *yUL = RoundDown(*yUL, rounding); yLL = RoundUp( yLL, rounding); } else { yLL = y_1 < y_2 ? y_1 : y_2; /* lowest value at bottom */ *yUL = y_1 > y_2 ? y_1 : y_2; /* highest value at top */ *yUL = RoundUp( *yUL, rounding); yLL = RoundDown( yLL, rounding); } *nrRows = (size_t)ceil(fabs(yLL - *yUL)/cellSize); }
static int QuickSort(INT4 partToSort, INT4 nrCells, const MAP_REAL8 *in, /* Read-write input map */ MAP_INT4 *tmp) /* read-write index temporary map */ { int left = partToSort; int right = nrCells - 1; int i, pointer = 2; int *stack = NULL; /* contains partitions to do */ /* Perform quicksort on the tmp map and to modify the output map * later. */ do { if (right > left) { i = Partition(tmp, in, left, right); if (ChkReallocFree((void **)&stack, (pointer + 2) * sizeof(INT4))) return 1; if (i - left > right - i) { stack[pointer] = left; stack[pointer + 1] = i - 1; left = i + 1; } else { stack[pointer] = i + 1; stack[pointer + 1] = right; right = i - 1; } pointer += 2; } else { pointer -= 2; /* other partition */ POSTCOND(pointer >= 0); left = stack[pointer]; right = stack[pointer + 1]; } } while (pointer != 0); PRECOND(stack != NULL); Free(stack); return 0; }
static int CloneOption( const char *name) { ATTRIBUTES a; if (FileStat(name) != 2) { return RetError(1,"file '%s' exists, give new (non-existing) name",name); } if (DefaultCloneAttr(&a)) return 1; a.cloneCreation = TRUE; switch(MakeCloneMenu(&a, name)) { case 0: return 1; case 1: return CreateMap(name, &a); case 2: fprintf(stderr,"No map created\n"); return 0; } POSTCOND(FALSE); return 1; }
static void Add2Lines( HOR_CUT_LINE *l, int nrLines, int xCeil, REAL8 c, REAL8 s, REAL8 x, REAL8 y ) { REAL8 xRot = (x*c)-(y*s); REAL8 yRot = (x*s)-(y*c); int xInd = ((int)floor(xRot))+(int)xCeil; POSTCOND(xInd >= 0 && xInd < nrLines); if (IS_MV_REAL4(&(l[xInd].start.f))) { l[xInd].start.f = POSSIBLE_DATA_LOSS(REAL4,yRot); l[xInd].end.f = POSSIBLE_DATA_LOSS(REAL4,yRot); } l[xInd].start.f = POSSIBLE_DATA_LOSS(REAL4,MIN(l[xInd].start.f, yRot)); l[xInd].end.f = POSSIBLE_DATA_LOSS(REAL4,MAX(l[xInd].end.f, yRot)); (void)nrLines; // shut up compiler }
static int EditOption( const char *name) { ATTRIBUTES a; MAP *in = Mopen(name, M_READ_WRITE); if (in == NULL || ReadAttr(&a,in,FALSE)) { if (in != NULL) Mclose(in); return RetError(1,"while reading '%s': %s",name,MstrError()); } if (a.version != 2) return RetError(1,"'%s' is not a version 2 map, no edits possible"); a.cloneCreation = FALSE; switch(MakeCloneMenu(&a, name)) { case 0: return 0; case 1: return SetAndCloseMap(in, &a); case 2: fprintf(stderr,"No map attributes written\n"); return 0; } POSTCOND(FALSE); return 1; }
/* Calculates the spread value. * The value is determined according to friction and the position of the * neighbors. If the neighbors are corner neighbors, the average * friction is multiplied with the diagonal, else with the side. * Returns the spread value. */ static REAL8 CalcSpreadValue( INT4 *id, /* write-only id */ const MAP_REAL8 *outCost, /* output costs */ const MAP_INT4 *outId, /* id map from spread */ const MAP_REAL8 *friction, /* friction map */ int r, /* row current cell */ int c, /* column curr. cell */ REAL8 f) /* friction value (r, c) */ { REAL8 costs, costVal, fricNxt, minCosts; int i, rNext, cNext; INT4 newId = 0; /* id spread point of min. cost */ minCosts = REAL8_MAX; /* minimum costs until now */ FOR_ALL_LDD_NBS(i) { rNext = RNeighbor(r, i); cNext = CNeighbor(c, i); if(outCost->Get(&costVal, rNext, cNext, outCost) && (friction->Get(&fricNxt, rNext, cNext, friction))) { costs = (f + fricNxt) / 2; costs *= (Corner(i) == FALSE) SCALE; costs += costVal; if(costs < minCosts) { /* cheapest path from neighbor to r,c */ minCosts = costs; outId->Get(&newId, rNext, cNext, outId); *id = newId; POSTCOND(*id != 0); } } } *id = newId; /* id from cheapest neighbor */ return minCosts; /* minimum costs to get to r, c */ }
/* Parses a key, checks whether or not it is legal. * Returns * 1 if the key is illegal (a nested error message is printed) * , 0 if succesfull. */ static int ParseKey( LOOK_UP_KEY *k, /* write-only key, if k->t == TEST_NOKEY * then the end of file is reached */ CSF_VS vs) /* value scale */ { typedef enum STATE { STATE_START, STATE_LOWNUM, STATE_COMMA, STATE_HIGHNUM, STATE_HIGHTOKEN } STATE; STATE state = STATE_START; int t; /* token */ long startLineNr = LexGetLineNr(); while(1) { t = LexGetToken(); if (t >= 0 && LexGetLineNr() != startLineNr) { if (state == STATE_START) /* parsed empty line */ startLineNr = LexGetLineNr(); else t = LEX_EOL; } switch(state) { case STATE_START: switch(t) { case LEX_NUMBER: k->t = TEST_ONE; if (SetNumber(k, TRUE, vs)) return 1; return 0; case '[' : k->t = TEST_GE_INF; state = STATE_LOWNUM; break; case '<' : k->t = TEST_GT_INF; state = STATE_LOWNUM; break; case 0 : k->t = TEST_NOKEY; return 0; default : return IllegalState(k,t,"$[<"); } break; case STATE_LOWNUM: PRECOND(k->t == TEST_GE_INF || k->t == TEST_GT_INF); switch(t) { case LEX_NUMBER: if (SetNumber(k, TRUE, vs)) return 1; state = STATE_COMMA; break; case ',': k->t = TEST_INF_INF; state = STATE_HIGHNUM; break; default : return IllegalState(k,t,"$,"); } break; case STATE_COMMA: if (t != ',') return IllegalState(k,t,","); state = STATE_HIGHNUM; break; case STATE_HIGHNUM: POSTCOND(k->t==TEST_GE_INF||k->t==TEST_GT_INF ||k->t==TEST_INF_INF); switch(t) { case LEX_NUMBER: if (SetNumber(k, FALSE, vs)) return 1; state = STATE_HIGHTOKEN; if (k->t != TEST_INF_INF && (k->l > k->h) ) { k->t = TEST_ERROR; // pcrcalc/test69 return RetErrorNested(1,"low value ('%g') of range larger than high value ('%g')", k->l,k->h); } break; case ']': case '>': /* already set, by choosing * intermediate states of k->t */ return 0; default : return IllegalState(k,t,"$]>"); }break; case STATE_HIGHTOKEN: POSTCOND(k->t==TEST_GE_INF||k->t==TEST_GT_INF ||k->t==TEST_INF_INF); switch(t) { /* inc over enums, that's why particular order */ case ']': k->t += 3; return 0; case '>': k->t += 6; return 0; default : return IllegalState(k,t,"]>"); } break; } /* eoswitch state */ } /* eowhile */ }
/* get the number of grey palette entries * MgetNrGreyPaletteEntries returns the number of grey tupels * of the grey palette. Each tuple is one UINT2 * words describing the intensity: low, 0 is black, high is white. * returns * the number of grey tuples, * or 0 if not available or in case of error */ size_t MgetNrGreyPaletteEntries(MAP *m) /* the map to get it from */ { size_t s = (size_t)CsfAttributeSize(m, ATTR_ID_GREY_PAL); POSTCOND( (s % (sizeof(UINT2))) == 0); return s / (sizeof(UINT2)); }
/* Performs the spread function using the breadth-first strategy. * All neighbors from current cell are checked on getting a cheaper path * from current cell. All cells in the coordlist are checked. Every time * a neighbor is found which gets a new cost value, its neighbors are * checked too. * Returns 0 if no error occurs, 1 otherwise. */ static int PerformSpread( MAP_REAL8 *outCost, /* read-write output costs */ MAP_INT4 *outId, /* read-write output id map */ NODE *coordList, /* read-write list of cells */ const MAP_REAL8 *friction, /* friction map */ const MAP_REAL8 *maxCost) /* max cost map */ { int rNext, cNext, rowNr, colNr, i; REAL8 f; /* friction of current cell */ REAL8 s, newS; /* old & new spreadval. of curr. cell */ PRECOND(outCost->GetGetTest(outCost) == GET_MV_TEST); PRECOND(outId->GetGetTest(outId) == GET_MV_TEST); PRECOND(friction->GetGetTest(friction) == GET_MV_TEST); PRECOND(maxCost->GetGetTest(maxCost) == GET_MV_TEST); while(coordList != NULL) { INT4 id; /* id of current cell */ rowNr = coordList->rowNr; /* cell from which is spread */ colNr = coordList->colNr; /* (source cell ) */ coordList = RemFromList(coordList); /* unable */ id = Set0BitMatrix(inList,rowNr,colNr); POSTCOND(id != 0); /* was set */ AppDynamicProgress(); FOR_ALL_LDD_NBS(i) { /* find new spread value for all neighbors */ rNext = RNeighbor(rowNr, i); cNext = CNeighbor(colNr, i); if(friction->Get(&f, rNext, cNext, friction) && outId->Get(&id, rNext, cNext, outId)) { INT4 newId = 0; if(id != 0) outCost->Get(&s, rNext, cNext, outCost); /* already visited */ newS = CalcSpreadValue(&newId, outCost, outId, friction, rNext, cNext, f); if(newId != 0 && (id == 0 || AppCastREAL4(newS) < s)) { /* a cheaper or first route to this cell * found, inspect the neighbors too. */ REAL8 maxCostVal; BOOL maxCostReached ; maxCost->Get(&maxCostVal, rNext, cNext, maxCost); maxCostReached = maxCostVal <= newS; if (!maxCostReached) { outCost->Put(newS, rNext, cNext, outCost); /* new costs */ outId->Put(newId, rNext, cNext, outId); /* new id */ coordList = AddToList(coordList, rNext, cNext); if(coordList == NULL) return 1; } } } } } /* POSTCOND(coordList == NULL); */ return 0; }
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 */ }
/* 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 */ }
/* 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 */
/* kk * returns allocated list of records, NULL in case of error (stored * in ErrorNested */ static LOOK_UP_KEY *ReadLookupRecs( size_t *nrCols, /* write-only */ size_t *nrRecs, /* write-only */ size_t nrKeysExp,/* numbers of keys expected, only relevant * if vsTargetValue != VS_UNDEFINED * this is exclusive the targetColumn */ CSF_VS vsTargetVal, /* if VS_UNDEFINED then skip test on exact number * of columns (= nrKeysExp+1) */ FILE *tableFile) { size_t n,nrK,c = DetectNrColsTable(tableFile); LOOK_UP_KEY *k = NULL; long recStartAt=0; if (c == 0) goto error; if (c == 1 && vsTargetVal != VS_UNDEFINED ) { ErrorNested("only 1 column found"); return NULL; } if (vsTargetVal != VS_UNDEFINED && c != (nrKeysExp+1)) { ErrorNested("contains %s columns ('%d' read,'%d' expected)", (c < (nrKeysExp+1) ? "not enough" : "too many"), c, nrKeysExp+1); goto error; } LexInstall(tableFile, "[]<>,"); for (nrK = n = 0; /* break from code */ ; n++) { CSF_VS vs = VS_UNDEFINED; if (n == nrK) { nrK += 40; if (ChkReallocFree((void **)&k,nrK * sizeof(LOOK_UP_KEY))) return NULL; } if (vsTargetVal != VS_UNDEFINED && (n%c) == nrKeysExp) vs = vsTargetVal; ParseKey(k+n, vs); if (k[n].t == TEST_NOKEY) { if ( (n%c)==0 ) break; else goto notEnough; } if (k[n].t == TEST_ERROR) { ErrorNested("while reading at line '%ld' column '%d'", LexGetLineNr(), (n%c)+1); goto error; } if (vsTargetVal != VS_UNDEFINED && (n%c) == nrKeysExp && k[n].t != TEST_ONE ) { ErrorNested( "value field at line '%ld' column '%d' is not a single value" , LexGetLineNr(), (n%c)+1); goto error; } if ( (n%c)==0) /* start new record */ { if (recStartAt == LexGetLineNr()) /* prev had more */ { ErrorNested( "Too many columns on line '%ld', expected '%d' columns", recStartAt,c); goto error; } recStartAt = LexGetLineNr(); } else /* add to this record */ { if (recStartAt != LexGetLineNr()) /* this does not have enough */ { notEnough: ErrorNested( "Not enough columns on line '%ld', expected '%d' columns", recStartAt,c); goto error; } } } /* eofor */ POSTCOND( (n % c) == 0); *nrCols = c; *nrRecs = n/c; return k; error: Free(k); return NULL; }
/* read a lookup or cross table * ReadLookupTable reads a table in matrix or table format. * The exact number of columns is not checked, unless outputVs * not equal to VS_UNDEFINED. * The number of actual columns read is plus one for the key column * Errors are printed in ErrorNested. * Returns the lookup table or NULL in case of an error. */ LOOK_UP_TABLE *ReadLookupTable( FILE *f, /* the tablefile */ const CSF_VS *keyVs, /* valuescales of key columns, * undefined if outputVs == VS_UNDEFINED */ size_t nrKeys, /* > 0 * undefined if outputVs == VS_UNDEFINED */ CSF_VS outputVs) /* VS_UNDEFINED if we don't care */ { size_t r,c,nrCols, nrRecs; LOOK_UP_KEY *k; LOOK_UP_TABLE *t; size_t nrColsExp; BOOL matrRead = (nrKeys == 2 && app2dMatrix); k = ReadLookupRecs(&nrCols, &nrRecs, nrKeys, matrRead ? VS_UNDEFINED : outputVs, f); if (outputVs == VS_UNDEFINED) { nrColsExp = nrCols; nrKeys = nrCols-1; keyVs = NULL; } else nrColsExp = nrCols; if (k == NULL || (t = ChkMalloc(sizeof(LOOK_UP_TABLE))) == NULL) return NULL; t->nrKeys = nrKeys; t->keyVs = NULL; t->records = NULL; t->searchMethod = SEARCH_LINEAR; if (matrRead) { /* build lookup from matrix and check matrix output/target values */ size_t i; t->nrRecords = (nrRecs-1)*(nrCols-1); t->nrMatrCols = nrCols-1; t->nrKeys = 2; /* CW */ if (t->nrRecords <= 0) { ErrorNested("matrix must have at least 2 rows and 2 columns"); goto error; } if (AllocLookupTable(t)) goto error; for (r=0,i=0; i < nrRecs*nrCols; i++) if ( (i/nrCols) != 0 /* not first row */ && (i%nrCols) != 0 ) /* not first col */ { /* col index is key 0 */ t->records[r][0] = k[i%nrCols]; /* row index is key 1 */ t->records[r][1] = k[nrCols*(i/nrCols)]; /* outputValue */ t->records[r++][2] = k[i]; if (CheckMatrixCell(i/nrCols,i%nrCols,k+i,outputVs)) goto error; } POSTCOND(r == t->nrRecords); } else /* table (not matrix) */ { t->nrRecords = nrRecs; if (nrColsExp > nrCols) { ErrorNested("not enough columns, read '%d' expected '%d' columns", nrCols, nrColsExp); goto error; } if (AllocLookupTable(t)) goto error; for(r=0; r < nrRecs; r++) (void)memcpy(t->records[r],k+(nrCols*r),nrColsExp*sizeof(LOOK_UP_KEY)); } Free(k); if (keyVs != NULL) (void)memcpy(t->keyVs, keyVs, t->nrKeys*sizeof(CSF_VS)); else for (r = 0; r < t->nrKeys; r++) t->keyVs[r] = VS_UNDEFINED; t->keyVs[t->nrKeys] = outputVs; /* adjust for directional */ nrCols = nrKeys + (outputVs != VS_UNDEFINED); for (c=0; c<nrCols; c++) if (t->keyVs[c] == VS_DIRECTION) for (r=0; r<t->nrRecords; r++) { if (LOW_DEFINED(t->records[r][c].t)) CnvrtDirectional(&(t->records[r][c].l)); if (HIGH_DEFINED(t->records[r][c].t)) CnvrtDirectional(&(t->records[r][c].h)); } return t; error: Free(k); FreeLookupTable(t); return NULL; }
/* Determines all lowest neighbors and gives them output. * All lowest neighbors from current cell are put at the beginning of * the list (depth-first) and the stream is added to their output value. * Returns list if successful, NULL when memory allocation failed. */ static NODE *DoNeighbors( MAP_REAL8 * out, /* read-write output map */ NODE *list, /* read-write list */ const MAP_REAL8 * dem, /* dem map */ const MAP_REAL8 * points, /* points map */ int r, /* current cell row */ int c, /* current cell column */ REAL8 drainVal) /* value to drain down */ { NODE *list2 = NULL; /* list of lowest neighbors */ REAL8 dropMax = 0; /* maximal drop value */ REAL8 dropVal = 0; /* maximal drop value */ int i, nrPaths = 0; /* nr of outgoing paths */ REAL8 demVal, newDem, outVal, pntVal; /* dem value * and output value of old and new cell and the * point value of both to check on MV. */ PRECOND(dem->GetGetTest(dem) == GET_MV_TEST); PRECOND(points->GetGetTest(points) == GET_MV_TEST); PRECOND(out->GetGetTest(out) == GET_MV_TEST); PRECOND(dem->Get(&demVal, r, c, dem)); PRECOND(out->Get(&outVal, r, c, out)); dem->Get(&demVal, r, c, dem); /* height original cell */ out->Get(&outVal, r, c, out); /* output original cell */ for(i = 1; i <= NR_LDD_DIR; i++) { /* check all neighbors */ int rNext = RNeighbor(r, i); int cNext = CNeighbor(c, i); if(dem->Get(&newDem, rNext, cNext, dem) && /* no MV */ points->Get(&pntVal, rNext, cNext, points) &&/* no MV */ (i != LDD_PIT) && /* skip cell itself */ (0 < (demVal - newDem))) /* lower than current cell */ { REAL8 dist = (Corner(i) == FALSE) SCALE; dropVal = (demVal - newDem) / dist; if(dropMax <= dropVal) { NODE *tmp; if(dropMax < dropVal) { /* all previous found neighbors * were not the lowest -> reset. */ list2 = FreeList(list2); POSTCOND(list2 == NULL); nrPaths = 0; dropMax = dropVal; } nrPaths++; tmp = LinkToList(list2, rNext, cNext); if(tmp == NULL) { FreeList(list2); FreeList(list); return NULL; } list2 = tmp; } } } drainVal /= nrPaths; /* divide between steepest paths */ while(list2 != NULL) { PRECOND(out->Get(&outVal, list2->rowNr, list2->colNr, out)); out->Get(&outVal, list2->rowNr, list2->colNr, out); outVal += drainVal; out->Put(outVal, list2->rowNr, list2->colNr, out); list = LinkChkReal(list, list2->rowNr, list2->colNr, drainVal); if(list == NULL) { FreeList(list2); return NULL; } list2 = RemFromList(list2); } POSTCOND(list != NULL); /* result HasLowerNeighbor was TRUE */ return list; }
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 */