diff options
Diffstat (limited to 'src/cd_util.c')
-rw-r--r-- | src/cd_util.c | 285 |
1 files changed, 285 insertions, 0 deletions
diff --git a/src/cd_util.c b/src/cd_util.c new file mode 100644 index 0000000..033fac6 --- /dev/null +++ b/src/cd_util.c @@ -0,0 +1,285 @@ +/** \file + * \brief Utilities + * + * See Copyright Notice in cd.h + */ + +#include <stdlib.h> +#include <string.h> +#include <ctype.h> +#include <stdio.h> +#include <memory.h> +#include <math.h> + + +#include "cd.h" + +#include "cd_private.h" + + +int cdRound(double x) +{ + return _cdRound(x); +} + +/* Returns a table to speed up zoom in discrete zoom rotines. + Adds the min parameter and allocates the table using malloc. + The table should be used when mapping from destiny coordinates to + source coordinates (src_pos = tab[dst_pos]). + dst_len is the full destiny size range. + src_len is only the zoomed region size, usually max-min+1. +*/ +int* cdGetZoomTable(int dst_len, int src_len, int src_min) +{ + int dst_i, src_i; + double factor; + int* tab = (int*)malloc(dst_len*sizeof(int)); + + factor = (double)(src_len) / (double)(dst_len); + + for(dst_i = 0; dst_i < dst_len; dst_i++) + { + src_i = cdRound((factor*(dst_i + 0.5)) - 0.5); + tab[dst_i] = src_i + src_min; + } + + return tab; +} + +/* funcao usada para calcular os retangulos efetivos de zoom + de imagens clientes. Pode ser usada para os eixos X e Y. + + canvas_size - tamanho do canvas (canvas->w, canvas->h) + cnv_rect_pos - posicao no canvas onde a regiao sera´ desenhada (x, y) + cnv_rect_size - tamanho da regiao no canvas com zoom (w, h) + img_rect_pos - posicao na imagem da regiao a ser desenhada (min) + img_rect_size - tamanho da regiao na imagem (max-min+1) + + calcula o melhor tamanho a ser usado + retorna 0 se o retangulo resultante e´ nulo +*/ +int cdCalcZoom(int canvas_size, + int cnv_rect_pos, int cnv_rect_size, + int *new_cnv_rect_pos, int *new_cnv_rect_size, + int img_rect_pos, int img_rect_size, + int *new_img_rect_pos, int *new_img_rect_size, + int is_horizontal) +{ + int offset; + float zoom_factor = (float)img_rect_size / (float)cnv_rect_size; + + /* valores default sem otimizacao */ + *new_cnv_rect_size = cnv_rect_size, *new_cnv_rect_pos = cnv_rect_pos; + *new_img_rect_size = img_rect_size, *new_img_rect_pos = img_rect_pos; + + if (cnv_rect_size > 0) + { + /* se posicao no canvas > tamanho do canvas, fora da janela, nao desenha nada */ + if (cnv_rect_pos >= canvas_size) + return 0; + + /* se posicao no canvas + tamanho da regiao no canvas < 0, fora da janela, nao desenha nada */ + if (cnv_rect_pos+cnv_rect_size < 0) + return 0; + + /* se posicao no canvas < 0, entao comeca fora do canvas melhor posicao no canvas e' 0 + E o tamanho e' reduzido do valor negativo */ + if (cnv_rect_pos < 0) + { + /* valores ajustados para cair numa vizinhanca de um pixel da imagem */ + offset = (int)ceil(cnv_rect_pos*zoom_factor); /* offset is <0 */ + offset = (int)ceil(offset/zoom_factor); + *new_cnv_rect_pos -= offset; + *new_cnv_rect_size += offset; + } + + /* se posicao no canvas + tamanho da regiao no canvas > tamanho do canvas, + termina fora do canvas entao + o tamanho da regiao no canvas e' o tamanho do canvas reduzido da posicao */ + if (*new_cnv_rect_pos+*new_cnv_rect_size > canvas_size) + { + offset = (int)((*new_cnv_rect_pos+*new_cnv_rect_size - canvas_size)*zoom_factor); + *new_cnv_rect_size -= (int)(offset/zoom_factor); /* offset is >0 */ + } + } + else + { + /* cnv_rect_size tamanho negativo, significa imagem top down */ + /* calculos adicionados pela Paula */ + + /* se posicao no canvas + tamanho no canvas (xmin+1) >= tamanho do canvas, fora da janela, nao desenha nada */ + if (cnv_rect_pos+cnv_rect_size >= canvas_size) + return 0; + + /* se posicao da imagem com zoom (xmax) < 0, fora da janela, nao desenha nada */ + if (cnv_rect_pos < 0) + return 0; + + /* se posicao com zoom (xmax) >= tamanho do canvas, posicao da imagem com zoom e' o tamanho do canvas menos um + tambem o tamanho e' reduzido do valor negativo */ + if (cnv_rect_pos >= canvas_size) + { + *new_cnv_rect_pos = canvas_size-1; + *new_cnv_rect_size = cnv_rect_size + (cnv_rect_pos - *new_cnv_rect_pos); + } + + /* se posicao + tamanho com zoom (xmin+1) < 0, + entao o tamanho com zoom e' a posição + 1 */ + if (cnv_rect_pos+cnv_rect_size < 0) + *new_cnv_rect_size = -(*new_cnv_rect_pos + 1); + } + + /* agora ja' tenho tamanho e posicao da regiao no canvas, + tenho que obter tamanho e posicao dentro da imagem original, + baseado nos novos valores */ + + /* tamanho da regiao na imagem e' a conversao de zoom para real do tamanho no canvas */ + *new_img_rect_size = (int)(*new_cnv_rect_size * zoom_factor + 0.5); + + if (is_horizontal) + { + /* em X, o offset dentro da imagem so' existe se houver diferenca entre a posicao inicial da + imagem e a posicao otimizada (ambas da imagem com zoom) */ + if (*new_cnv_rect_pos != cnv_rect_pos) + { + offset = *new_cnv_rect_pos - cnv_rect_pos; /* offset is >0 */ + *new_img_rect_pos += (int)(offset*zoom_factor); + } + } + else + { + /* em Y, o offset dentro da imagem so' existe se houver diferenca entre a posicao + final (posição inicial + tamanho) da imagem e a posicao otimizada (ambas da + imagem com zoom) */ + if ((cnv_rect_pos + cnv_rect_size) != (*new_cnv_rect_pos + *new_cnv_rect_size)) + { + /* offset is >0, because Y axis is from top to bottom */ + offset = (cnv_rect_pos + cnv_rect_size) - (*new_cnv_rect_pos + *new_cnv_rect_size); + *new_img_rect_pos += (int)(offset*zoom_factor); + } + } + + return 1; +} + +int cdGetFileName(const char* strdata, char* filename) +{ + const char* start = strdata; + if (!strdata || strdata[0] == 0) return 0; + + if (strdata[0] == '\"') + { + strdata++; /* the first " */ + while(*strdata && *strdata != '\"') + *filename++ = *strdata++; + strdata++; /* the last " */ + } + else + { + while(*strdata && *strdata != ' ') + *filename++ = *strdata++; + } + + if (*strdata == ' ') + strdata++; + + *filename = 0; + return (int)(strdata - start); +} + +void cdNormalizeLimits(int w, int h, int *xmin, int *xmax, int *ymin, int *ymax) +{ + *xmin = *xmin < 0? 0: *xmin < w? *xmin: (w - 1); + *ymin = *ymin < 0? 0: *ymin < h? *ymin: (h - 1); + *xmax = *xmax < 0? 0: *xmax < w? *xmax: (w - 1); + *ymax = *ymax < 0? 0: *ymax < h? *ymax: (h - 1); +} + +int cdCheckBoxSize(int *xmin, int *xmax, int *ymin, int *ymax) +{ + if (*xmin > *xmax) _cdSwapInt(*xmin, *xmax); + if (*ymin > *ymax) _cdSwapInt(*ymin, *ymax); + + if ((*xmax-*xmin+1) <= 0) + return 0; + + if ((*ymax-*ymin+1) <= 0) + return 0; + + return 1; +} + +int cdfCheckBoxSize(double *xmin, double *xmax, double *ymin, double *ymax) +{ + if (*xmin > *xmax) _cdSwapDouble(*xmin, *xmax); + if (*ymin > *ymax) _cdSwapDouble(*ymin, *ymax); + + if ((*xmax-*xmin+1) <= 0) + return 0; + + if ((*ymax-*ymin+1) <= 0) + return 0; + + return 1; +} + +void cdRotatePoint(cdCanvas* canvas, int x, int y, int cx, int cy, int *rx, int *ry, double sin_theta, double cos_theta) +{ + double t; + + /* translate to (cx,cy) */ + x = x - cx; + y = y - cy; + + /* rotate */ + if (canvas->invert_yaxis) + { + t = (x * cos_theta) + (y * sin_theta); *rx = _cdRound(t); + t = -(x * sin_theta) + (y * cos_theta); *ry = _cdRound(t); + } + else + { + t = (x * cos_theta) - (y * sin_theta); *rx = _cdRound(t); + t = (x * sin_theta) + (y * cos_theta); *ry = _cdRound(t); + } + + /* translate back */ + *rx = *rx + cx; + *ry = *ry + cy; +} + +void cdRotatePointY(cdCanvas* canvas, int x, int y, int cx, int cy, int *ry, double sin_theta, double cos_theta) +{ + double t; + + /* translate to (cx,cy) */ + x = x - cx; + y = y - cy; + + /* rotate */ + if (canvas->invert_yaxis) + { + t = -(x * sin_theta) + (y * cos_theta); *ry = _cdRound(t); + } + else + { + t = (x * sin_theta) + (y * cos_theta); *ry = _cdRound(t); + } + + /* translate back */ + *ry = *ry + cy; +} + +int cdStrEqualNoCase(const char* str1, const char* str2) +{ + int i = 0; + if (str1 == str2) return 1; + if (!str1 || !str2 || tolower(*str1) != tolower(*str2)) return 0; + + while (str1[i] && str2[i] && tolower(str1[i])==tolower(str2[i])) + i++; + if (str1[i] == str2[i]) return 1; + + return 0; +} + |