📄 utils.cpp
字号:
default:
if((unsigned char)str[i] <= 127) TmpTxt[j++]=str[i];
else {
if(mbtowc(&wc, str+i, 1) >0) j += sprintf(TmpTxt+j,
"&#%d;", ((unsigned short)wc));
}
}
}
TmpTxt[j] = 0;
return(TmpTxt);
}
// split string str into array of strings using sep as separator
// return number of lines created in nl
char **split(char *str, char sep, int *nl)
{
int i, j, k, l, ns;
char **ptr, *txt;
if(!str || !sep) return 0L;
if(!(txt = strdup(str))) return 0L;
k = (int)strlen(txt);
for(i = ns = 0; i < k; i++) if(txt[i] == sep) ns++;
if(!(ptr = (char**)calloc(ns+2, sizeof(char*)))){
free(txt); return 0L;
}
for(i = j = l = 0; i < k; i++) {
if(txt[i] == sep) {
txt[i] = 0; ptr[l++] = strdup(txt+j); j = i+1;
}
}
ptr[l++] = strdup(txt+j); if(nl) *nl = l; free(txt);
return ptr;
}
char *fit_num_rect(anyOutput *o, int max_width, char *num_str)
{
int i, j, k, w, h, slen;
char mant[20], expo[20], fmt[10];
double num;
o->oGetTextExtent(num_str, slen = strlen(num_str), &w, &h);
if(w < (max_width-5)) return num_str;
//first try to remove leading zero from exponent
for(i = 0; i < slen; i++) if(num_str[i] == 'e') break;
if(num_str[i] == 'e') while (num_str[i+2] == '0') {
for(j = i+2; num_str[j]; j++) num_str[j] = num_str[j+1];
o->oGetTextExtent(num_str, slen = strlen(num_str), &w, &h);
if(w < (max_width-5)) return num_str;
}
//no success: reduce the number of digit by rounding
for(i = k = 0; i <= slen; i++){
if(num_str[i] == '.') k = i;
if((mant[i] = num_str[i]) == 'e' || mant[i] == 0) break;
}
if(num_str[i] =='e') mant[i] = 0; k = i - k-1;
for(j = 0; num_str[i]; j++, i++) expo[j] = num_str[i]; expo[j] = 0;
sscanf(mant, "%lf", &num);
if(k >0) do {
sprintf(fmt, "%s.%dlf%s", "%", k, expo);
sprintf(num_str, fmt, num); k--;
o->oGetTextExtent(num_str, slen = strlen(num_str), &w, &h);
if(w < (max_width-5)) return num_str;
}while (k >= 0);
//cannot fit: return hash marks instead
for(i = w = 0; w < (max_width-5); i++) {
sprintf(num_str+i, "#");
o->oGetTextExtent(num_str, slen = strlen(num_str), &w, &h);
}
num_str[i-1] = 0; return num_str;
}
//----------------------------------------------------------------------------
// bounding rectangle utilities
//----------------------------------------------------------------------------
void SetMinMaxRect(RECT *rc, int x1, int y1, int x2, int y2)
{
if(x1 > x2) {
rc->left = x2; rc->right = x1;
}
else {
rc->left = x1; rc->right = x2;
}
if(y1 > y2) {
rc->top = y2; rc->bottom = y1;
}
else {
rc->top = y1; rc->bottom = y2;
}
}
void UpdateMinMaxRect(RECT *rc, int x, int y)
{
if(x < rc->left) rc->left = x;
if(x > rc->right) rc->right = x;
if(y < rc->top) rc->top = y;
if(y > rc->bottom) rc->bottom = y;
}
void IncrementMinMaxRect(RECT *rc, int i)
{
rc->left -= i; rc->right += i;
rc->top -= i; rc->bottom += i;
}
bool IsInRect(RECT *rc, int x, int y)
{
if(x < rc->left || x > rc->right ||
y < rc->top || y > rc->bottom) return false;
return true;
}
//----------------------------------------------------------------------------
// test if point (e.g. mouse position) is close to or iside a shape
//----------------------------------------------------------------------------
bool IsCloseToLine(POINT *p1, POINT *p2, int x, int y)
{
bool bFound = false;
int tmp, dx, dy;
//do not process single point
if(p1->x == p2->x && p1->y == p2->y) return false;
//point must be bracketed by p1:p2
if((x-2) > p1->x && (x-2) > p2->x) return false;
if((x+2) < p1->x && (x+2) < p2->x) return false;
if((y-2) > p1->y && (y-2) > p2->y) return false;
if((y+2) < p1->y && (y+2) < p2->y) return false;
if(abs(dx = (p2->x - p1->x)) < abs(dy = (p2->y - p1->y))) { //y dominant
tmp = (p1->x + ((y - p1->y) * dx)/dy);
if(x > (tmp-3) && x < (tmp+3)) bFound = true;
}
else { // x dominant
tmp = (p1->y + ((x - p1->x) * dy)/dx);
if(y > (tmp-3) && y < (tmp+3)) bFound = true;
}
return bFound;
}
bool IsCloseToPL(POINT p, POINT *pts, int cp)
{
int i;
for( i = 1; i < cp; i++) if(IsCloseToLine(pts+i-1, pts+i, p.x, p.y)) return true;
return false;
}
//test if poitn p is within the polygon pts of size cp
//note: the last point of the polypon should be equal to the first point,
// i.e. the polygon must be closed
int idx_point_on_line;
bool IsInPolygon(POINT *p, POINT *pts, int cp)
{
int tmp1 = 0, tmp2 = 0, tmp3, i;
for(i = 1; i < cp; i++) {
if((pts[i-1].x <= p->x && pts[i].x > p->x) || (pts[i-1].x > p->x && pts[i].x <= p->x)) {
tmp3 = ((p->x - pts[i-1].x)*(pts[i].y -pts[i-1].y))/(pts[i].x - pts[i-1].x);
tmp3 += pts[i-1].y;
if(p->y > tmp3) tmp1++;
else if(p->y < tmp3) tmp2++;
else return false; //ignore points on the line
}
}
return((tmp1 & 0x1) && (tmp2 & 0x1));
}
bool IsInPolygon3D(double x, double y, POINT3D *pts, int cp, int *us, int *ls)
{
int tmp1 = 0, tmp2 = 0, i, idx1, idx2;
double tmp3;
for(i = 1, idx1 = idx2 = -1; i < cp; i++) {
if((pts[i-1].x <= x && pts[i].x > x) || (pts[i-1].x > x && pts[i].x <= x)) {
tmp3 = ((x - pts[i-1].x)*(pts[i].y -pts[i-1].y))/(pts[i].x - pts[i-1].x);
tmp3 += pts[i-1].y;
if(y > tmp3){
tmp1++; idx1 = i;
}
else if(y < tmp3) {
tmp2++; idx2 = i;
}
else { //points is on the line
idx1 = idx2 = idx_point_on_line = i;
if(us) *us = idx1; if(ls) *ls = idx2;
return true;
}
}
}
//return an index to the bracketing sgments of the polygon
if(us) *us = idx1; if(ls) *ls = idx2;
return((tmp1 & 0x1) && (tmp2 & 0x1));
}
//return true if two rectangles overlap
bool OverlapRect(RECT *rc1, RECT *rc2)
{
if((rc1->left < rc2->right && rc1->right > rc2->left) ||
(rc2->left < rc1->right && rc2->right > rc1->left)) {
if((rc1->top < rc2->bottom && rc1->bottom > rc2->top) ||
(rc2->top < rc1->bottom && rc2->bottom > rc1->top))
return true;
}
return false;
}
//----------------------------------------------------------------------------
// collect points to a polygon
// keep number of points low by extrapolation
//----------------------------------------------------------------------------
void AddToPolygon(long *cp, POINT *pts, POINT *np)
{
int ix, iy;
long i = *cp;
if(i && pts[i-1].x == np->x && pts[i-1].y == np->y) return;
if(i < 2) { //accept first points of polygon
pts[i].x = np->x; pts[i].y = np->y; *cp = i+1;
return;
}
if(pts[i-1].x == pts[i-2].x && pts[i-1].x == np->x) {
if(np->y == pts[i-1].y) return;
if((np->y > pts[i-1].y && pts[i-1].y > pts[i-2].y) ||
(np->y < pts[i-1].y && pts[i-1].y < pts[i-2].y)) {
pts[i-1].x = np->x;
pts[i-1].y = np->y;
return;
}
}
if(pts[i-1].y == pts[i-2].y && pts[i-1].y == np->y) {
if(np->x == pts[i-1].x) return;
if((np->x > pts[i-1].x && pts[i-1].x > pts[i-2].x) ||
(np->x < pts[i-1].x && pts[i-1].x < pts[i-2].x)) {
pts[i-1].x = np->x;
pts[i-1].y = np->y;
return;
}
}
//try linear extrapolation
if((pts[i-1].x > pts[i-2].x && np->x > pts[i-1].x) ||
(pts[i-1].x < pts[i-2].x && np->x < pts[i-1].x)) {
ix = (pts[i-1].y != pts[i-2].y) ? (pts[i-2].x + ((np->y - pts[i-2].y) *
(pts[i-1].x - pts[i-2].x))/(pts[i-1].y - pts[i-2].y)) : 0;
iy = (pts[i-1].x != pts[i-2].x) ? (pts[i-2].y + ((np->x - pts[i-2].x) *
(pts[i-1].y - pts[i-2].y))/(pts[i-1].x - pts[i-2].x)) : 0;
if((ix && ix == np->x) || (iy && iy == np->y)) {
pts[i-1].x = np->x;
pts[i-1].y = np->y;
return;
}
}
//not explained by extrapolation, accept new point
pts[i].x = np->x;
pts[i].y = np->y;
*cp = i+1;
return;
}
//----------------------------------------------------------------------------
// create a circular polygon
//use circular Bresenham's algorithm to draw arcs
//Ref: C. Montani, R. Scopigno (1990) "Speres-To-Voxel Conversion", in:
// Graphic Gems (A.S. Glassner ed.) Academic Press, Inc.;
// ISBN 0-12-288165-5
//----------------------------------------------------------------------------
POINT *MakeArc(int ix, int iy, int r, int qad, long *npts)
{
int i, x, y, di, de, lim;
static POINT *pts, *rpts;
POINT np;
if(r < 1) return 0L;
if(!(pts = (POINT*) malloc((r+1)*8*sizeof(POINT))))return 0L;
for(i = *npts = 0; i < 4; i++) {
x = lim = 0; y = r; di = 2*(1-r);
if(qad & (1<<i))while (y >= lim){
if(di < 0) {
de = 2*di + 2*y -1;
if(de > 0) {
x++; y--; di += (2*x -2*y +2);
}
else {
x++; di += (2*x +1);
}
}
else {
de = 2*di -2*x -1;
if(de > 0) {
y--; di += (-2*y +1);
}
else {
x++; y--; di += (2*x -2*y +2);
}
}
switch(i) {
case 0: np.x = ix-y; np.y = iy+x; break;
case 1: np.x = ix+x; np.y = iy+y; break;
case 2: np.x = ix+y; np.y = iy-x; break;
case 3: np.x = ix-x; np.y = iy-y; break;
}
AddToPolygon(npts, pts, &np);
}
}
if(*npts < 3) return 0L;
if(rpts = (POINT*)realloc(pts, sizeof(POINT)*(*npts))) return rpts;
return pts;
}
//----------------------------------------------------------------------------
// display a marked polygon by displaying it with complement colors
//----------------------------------------------------------------------------
void InvertPolygon(POINT *pts, int nPts, LineDEF *Line, FillDEF *Fill, RECT *rc,
anyOutput *o, bool mark)
{
LineDEF *FillLine;
if(!Line || !Fill || !rc || !o) return;
FillLine = Fill->hatch;
if(mark) {
if(FillLine)FillLine->color ^= 0x00ffffffL;
Fill->color ^= 0x00ffffffL;
Line->color ^= 0x00ffffffL;
o->SetLine(Line);
o->SetFill(Fill);
o->oPolygon(pts, nPts);
Fill->color ^= 0x00ffffffL;
if(FillLine)FillLine->color ^= 0x00ffffffL;
Line->color ^= 0x00ffffffL;
InvertLine(pts, nPts, Line, 0L, o, mark);
}
else {
InvertLine(pts, nPts, Line, 0L, o, mark);
o->SetLine(Line);
o->SetFill(Fill);
o->oPolygon(pts, nPts);
}
if(rc) o->UpdateRect(rc, false);
}
//----------------------------------------------------------------------------
// display a marked line using complement colors
//----------------------------------------------------------------------------
void InvertLine(POINT *pts, int nPts, LineDEF *Line, RECT *rc,
anyOutput *o, bool mark)
{
LineDEF OldLine;
double minw = defs.GetSize(SIZE_DATA_LINE);
memcpy(&OldLine, Line, sizeof(LineDEF));
if(OldLine.width <= 0.001) memcpy(&OldLine, defs.GetLine(), sizeof(LineDEF));
OldLine.color = mark ? Line->color : 0x00ffffffL;
OldLine.width = OldLine.width < minw ? minw * 3.0 : OldLine.width *3.0;
o->SetLine(&OldLine);
o->oPolyline(pts, nPts);
OldLine.width = Line->width;
OldLine.color = mark ? Line->color ^ 0x00ffffffL : Line->color;
o->SetLine(&OldLine);
o->oPolyline(pts, nPts);
if(rc) o->UpdateRect(rc, false);
}
//----------------------------------------------------------------------------
// color utilitis
//----------------------------------------------------------------------------
// calculate distance between two colors
unsigned int ColDiff(DWORD col1, DWORD col2)
{
int ret = 0, d;
d = (col1 & 0xff) - (col2 & 0xff);
ret = isqr(d*d);
d = ((col1>>8) & 0xff) - ((col2>>8) & 0xff);
ret += isqr(d*d);
d = ((col1>>16) & 0xff) - ((col2>>16) & 0xff);
ret += isqr(d*d);
return ret;
}
//----------------------------------------------------------------------------
// interpolate between two colors
DWORD IpolCol(DWORD color1, DWORD color2, double fact)
{
DWORD col1, col2, col3, c1;
int i;
col1 = color1; col2 = color2; col3 = 0x0L;
for(i = 0; i < 3; i++) {
c1 = iround(fabs(((col1 & 0xff0000)>>16) * fact));
c1 += iround(fabs(((col2 & 0xff0000)>>16) *(1.0-fact)));
col3 |= c1 < 0xff ? c1 : 0xff;
col1 <<= 8; col2 <<= 8;
if(i < 2) col3 <<= 8;
}
return col3;
}
//----------------------------------------------------------------------------
// Random number generator with low sequential correlations.
// ran2 returns a number betwee 0.0f and 1.0f;
// Ref: W.H. Press, B.P. Flannery, S.A. Teukolsky, W.T. Veterling
// Numerical Recipe in C, The Art of Scientific Computing
// Cambridge University Press 1988, ISBN 0-521-35465-X
//----------------------------------------------------------------------------
#define M 714025
#define IA 1366
#define IC 150889
double ran2(long *idum)
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -