#include #include #include #include #include "easygraph.h" #include "easycolor.h" typedef struct _mode_graph_data { EG_VALUE value; int count; } GMODE; typedef struct _mode_color_data { COLOR color; int count; } CMODE; GMODE *gmode = NULL; CMODE *cmode = NULL; int gmodemaxnum = 0; int cmodemaxnum = 0; int gmodecurnum = 0; int cmodecurnum = 0; /* 二つの色が同じならば0, 違っていれば0以外を返す */ static int isEquivalentColor(COLOR *col1, COLOR *col2) { if (col1->red == col2->red && col1->green == col2->green && col1->blue == col2->blue) return 0; return 1; } static void dumpCMode() { CMODE *cur; int i; cur = cmode; i = 0; for (i = 0; i < cmodecurnum; i++) { fprintf(stderr, "[%d] mode=%d (%d,%d,%d)[%d,%d]\n", i, cur->count, cur->color.red, cur->color.green, cur->color.blue, cur->color.start, cur->color.end); cur++; } } /* static GMODE *initGraphModeData(int maxnum) { gmode = (GMODE *)calloc(maxnum, sizeof(GMODE)); if (!gmode) { fprintf(stderr, "initGraphModeData: memory allocation error.\n"); return NULL; } gmodecurnum = 0; gmodemaxnum = maxnum; return gmode; } */ static CMODE *initColorModeData(int maxnum) { cmodecurnum = 0; if (cmode && maxnum <= cmodemaxnum) { memset(cmode, 0, maxnum * sizeof(CMODE)); return cmode; } if (cmode) { free(cmode); cmode = NULL; cmodemaxnum = 0; } if (maxnum <= 0) { cmode = NULL; cmodemaxnum = 0; return NULL; } cmode = (CMODE *)malloc(maxnum * sizeof(CMODE)); if (!cmode) { fprintf(stderr, "initColorModeData: memory allocation error.\n"); return NULL; } memset(cmode, 0, maxnum * sizeof(CMODE)); cmodemaxnum = maxnum; return cmode; } static void termColorModeData() { if (cmode) free(cmode); cmodecurnum = cmodemaxnum = 0; } static int addColorModeData(COLOR *col) { CMODE *cur; int i; if (!col || !cmode) { fprintf(stderr, "addColorModeData: invalid argument.\n"); return 0; } cur = cmode; for (i = 0; i < cmodecurnum; i++) { if (isEquivalentColor(col, &cur->color) == 0) { cur->count++; break; } cur++; } if (i == cmodecurnum) { memcpy(&cur->color, col, sizeof(COLOR)); cur->count = 1; cmodecurnum++; } return cur->count; } static COLOR *findColorMode() { int max = 0; int i; CMODE *cur; CMODE *maxmode; cur = maxmode = cmode; max = cur->count; cur++; for (i = 1; i < cmodecurnum; i++) { if (cur->count > max) { max = cur->count; maxmode = cur; } } return &maxmode->color; } /* 指定した文字列に対応したBLEND値(enum型)を得る */ BLEND resolveBlend(char *string) { if (strcmp(string, "ave") == 0 || strcmp(string, "average") == 0) return average; if (strcmp(string, "min") == 0) return min; if (strcmp(string, "max") == 0) return max; if (strcmp(string, "mode") == 0) return mode; return NOBLEND; } /* 指定したBLEND値(enum型)に対応した文字列をareaに書き込む */ void getBlendName(BLEND ble, char *area, int len) { if (len <= BLEND_NAME_MAX_LEN) { fprintf(stderr, "getBlendName: too small area.\n"); return; } switch(ble) { case average: strcpy(area, "average"); break; case min: strcpy(area, "min"); break; case max: strcpy(area, "max"); break; case mode: strcpy(area, "mode"); break; default: strcpy(area, "NOBLEND"); } } /* bufの内容を指定の単位で指定のポリシで合成した値を返す */ /* 例) buf[] = {1, 2, 3, 4, 5, 6, 7, 8}, unit=4, blend=average */ /* ⇒buf先頭からunit個数分の値を合成して返す。この場合2.5を返す。*/ EG_VALUE blendGraph(EG_VALUE *buf, int unit, BLEND policy) { EG_VALUE value; int i, j, nMaxMode; MODE_STRUCT *modes; EG_VALUE temp; int bModeHit; value = 0.0; if(!buf) { fprintf(stderr, " ## blend -- buf pointer is NULL. ##\n"); return -1; } if (unit == 0) { fprintf(stderr, " ## blend -- unit is zero. ##\n"); return -1; } switch (policy) { case average: if (unit <= 0) { fprintf(stderr, "blend: unit is zero.\n"); exit(1); } value = 0; for (i = 0; i < unit; i++) { value += buf[i]; } value = value / unit; break; case max: value = buf[0]; for (i = 1; i < unit; i++) if (value < buf[i]) value = buf[i]; break; case min: value = buf[0]; for (i = 1; i < unit; i++) if (value > buf[i]) value = buf[i]; break; case mode: // 連続データだが、刻み幅を決めて離散データと見なすことはせず、 // 実数値が一致したものをカウントしていく。 // 最頻値が複数あるとき(共通の実数値が無いときも含む)は、 // データ順の早いものを採用する。(Excelと同様) modes = (MODE_STRUCT *)malloc(ENTRY_SIZE * unit); if (!modes) { fprintf(stderr, "memory alloc error.\n"); value = buf[0]; break; } onmemModeStructs++; for (i = 0; i < unit; i++) { // 初期化 //modes[i].mode_value = DBL_MIN; modes[i].mode_value = -1e+100; modes[i].mode_count = 0; bModeHit = 0; temp = buf[i]; for (j = 0; j < i; j++) { if (buf[j] == temp) { modes[j].mode_count++; bModeHit = 1; break; } } if (bModeHit == 0) { modes[i].mode_value = temp; modes[i].mode_count++; } } nMaxMode = 0; for (i = 0; i < unit; i++) { if (modes[i].mode_count > nMaxMode) { nMaxMode = modes[i].mode_count; value = modes[i].mode_value; } } free(modes); onmemModeStructs--; break; default: value = buf[0]; } return value; } /* bufの内容を指定の単位ずつに区切って値を計算して書き換える */ /* 戻り値は、書き換えた後の要素数とする */ /* 例) buf[] = {1, 2, 3, 4, 5, 6, 7, 8}, unit=3, blend=average */ /* ⇒buf = {2, 5, 7.5}にして、3を返す。 */ /* bufの内容がunitで割り切れない場合、 */ /* 最後の要素のみunit数以下の要素で計算する。 */ int blendGraphArray(EG_VALUE *buf, ssize_t num, int unit, BLEND policy) { int seedpos, afterpos; EG_VALUE value; seedpos = afterpos = 0; while (seedpos < num) { if (unit > num - seedpos) unit = num - seedpos; value = blendGraph(&buf[seedpos], unit, policy); fprintf(stderr, "seedpos=%d, afterpos=%d, value=%g\n", seedpos, afterpos, value); buf[afterpos] = value; seedpos += unit; afterpos++; } return afterpos; } /*****************************************************************************/ /* 指定範囲のカラー値を合成する */ /* [戻り値] 1:合成処理を行った, 0:合成処理を行わなかった(不要またはエラー) */ /* [副作用] unitとwidthの値が調整される */ /*****************************************************************************/ int blendColor(EasyColorTrack *ect, int start, int end, int unit, int width, BLEND policy) { EasyColor *ec; COLOR *blended; /* ブレンド済みのCOLOR構造体の配列 */ COLOR *current = NULL; /* オリジナルの現在のCOLOR構造体 */ COLOR *bcur = NULL; /* ブレンド中の現在のCOLOR構造体 */ COLOR *modecolor = NULL; int entrynum; int spos; int epos; int cpos; int cstart; int result = 0; int unitnum; int current_unitnum = 0; int count; int red, green, blue; if (!ect) { fprintf(stderr, "blendColor: invalid argument.\n"); return 0; } ec = ect->easycolors; if (!ec) return 0; /* EasyColorが0個なので何もせずに終了 */ /* 指定範囲の先頭のCOLOR構造体の位置を特定 */ current = ec->colors; for (spos = 0; spos < ec->colornum && current; spos++) { if (start <= current->end) break; current++; } /* 範囲が不正の場合はカラー情報無しにする */ if (spos >= ec->colornum) { ec->colornum = 0; free(ec->colors); onmemColors--; ec->colors = NULL; return 1; } /* 指定範囲の末尾のCOLOR構造体の位置を特定 */ for (epos = spos; epos < ec->colornum && current; epos++) { if (end <= current->end) break; current++; } if (epos == ec->colornum) epos = ec->colornum - 1; /* 必要なCOLOR構造体だけ残す */ if (spos > 0) { ec->colornum = epos - spos + 1; memmove(ec->colors, &ec->colors[spos], sizeof(COLOR) * ec->colornum); } else { ec->colornum = epos + 1; } current = ec->colors; if (current->start < start) { current->start = start; } else { start = current->start; } current = &ec->colors[epos]; if (end < current->end) { current->end = end; } else { end = current->end; } entrynum = end - start + 1; unitnum = entrynum / unit; if (entrynum % unit != 0) unitnum++; blended = (COLOR *)calloc(sizeof(COLOR), unitnum); if (!blended) { fprintf(stderr, "blendColor: memory allocation error.\n"); return 0; } onmemColors++; current = ec->colors; bcur = blended; red = green = blue = 0; /* 合成処理 */ switch (policy) { case average: count = 0; current_unitnum = 0; cstart = start; for (cpos = start; cpos <= end; cpos++) { if (cpos > current->end) { current++; } red += current->red; green += current->green; blue += current->blue; count++; if (count == unit || cpos == end) { bcur->red = red / count; bcur->green = green / count; bcur->blue = blue / count; bcur->start = cstart; bcur->end = cpos; current_unitnum++; bcur++; count = 0; cstart = cpos + 1; red = green = blue = 0; } } break; case mode: count = 0; current_unitnum = 0; cstart = start; initColorModeData(unit); for (cpos = start; cpos <= end; cpos++) { if (cpos > current->end) { current++; } addColorModeData(current); count++; if (count == unit || cpos == end) { modecolor = findColorMode(); bcur->red = modecolor->red; bcur->green = modecolor->green; bcur->blue = modecolor->blue; bcur->start = cstart; bcur->end = cpos; current_unitnum++; bcur++; count = 0; cstart = cpos + 1; initColorModeData(unit); } } termColorModeData(); break; default: result = 0; } free(ec->colors); onmemColors--; ec->colors = blended; ec->colornum = current_unitnum; ec->start = ec->colors[0].start; ec->end = ec->colors[ec->colornum - 1].end; ec->unit = unit; //dumpEasyColor(stderr, ec); return 1; }