📄 utils.cpp
字号:
{
static long iy, ir[98];
static int iff = 0;
int j;
if(*idum < 0 || iff == 0) {
iff = 1;
if((*idum = (IC-(*idum)) % M) < 0) *idum = -(*idum);
for(j = 1; j <= 97; j++) {
*idum = (IA*(*idum)+IC) % M;
ir[j] = (*idum);
}
*idum=(IA*(*idum)+IC) % M;
iy=(*idum);
}
j = 1+97 * iy/M;
if(j > 97 || j< 1) return 0.0f; //impossible
iy = ir[j];
*idum = (IA*(*idum)+IC) % M;
ir[j] = (*idum);
return (float) iy/M;
}
#undef IC
#undef IA
#undef M
//----------------------------------------------------------------------------
// integer square root
// calculate the largest number <= sqr(n)
// Christopher J. Musial in Graphics Gems II, page 37ff, page 610
// Academic Press, 1991
// modified
//----------------------------------------------------------------------------
unsigned long int isqr(unsigned long int n)
{
unsigned long int nextTrial, decrement;
if (nextTrial = n>>1) {
for ( ; ; ){
if(decrement = (nextTrial - n/nextTrial)>>1) nextTrial -= decrement;
else if(nextTrial * nextTrial > n) return nextTrial-1;
else return nextTrial;
}
}
return n;
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// multiply two rotation matrices
// see: Graphic Gems, A.S. Glassner ed.; Academic Press Inc.
// ISBN 0-12-286165-5, p.640
//
bool MatMul(double a[3][3], double b[3][3], double c[3][3])
{
int i, j, k;
bool success = true;
for(i = 0; i < 3; i++) {
for (j = 0; j < 3; j++) {
c[i][j] = 0.0;
for(k = 0; k < 3; k++) c[i][j] += a[i][k] * b[k][j];
if(c[i][j] < -.99999 || c[i][j] > .99999) success = false;
}
}
return success;
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//Return a format string depending on the range
//
char *GetNumFormat(double Magn)
{
if(Magn < -3.0) return("%0.2le");
if(Magn == -3.0) return("%0.4lf");
if(Magn == -2.0) return("%0.3lf");
if(Magn == -1.0) return("%0.2lf");
if(Magn == 0.0) return("%0.1lf");
if(Magn >= 5.0) return("%0.2le");
return("%0.0lf");
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//Delete a graphic object using the Id member of the class to select the
// the proper destructor
void DeleteGO(GraphObj *go)
{
if(!go) return;
if(!go->Id) {
//this will also set the Id member of the class
go->Command(CMD_SET_DATAOBJ, 0L, 0L);
}
if(go == CurrGO) CurrGO = 0L;
switch(go->Id) {
case GO_AXIS: delete((Axis*)go); break;
case GO_TICK: delete((Tick*)go); break;
case GO_GRIDLINE: delete((GridLine*)go); break;
case GO_GRIDLINE3D: delete((GridLine3D*)go); break;
case GO_SYMBOL: delete((Symbol*)go); break;
case GO_BUBBLE: delete((Bubble*)go); break;
case GO_BAR: delete((Bar*)go); break;
case GO_ERRBAR: delete((ErrorBar*)go); break;
case GO_ARROW: delete((Arrow*)go); break;
case GO_BOX: delete((Box*)go); break;
case GO_WHISKER: delete((Whisker*)go); break;
case GO_DROPLINE: delete((DropLine*)go); break;
case GO_DATALINE:
//we call ~DataLine for ~DataPolygon because variables are
// initialized in DataLine ??!!??!!
// otherwise we would crash with ~DataPolygon.
case GO_DATAPOLYGON: delete((DataLine*)go); break;
case GO_SPHERE: delete((Sphere*)go); break;
case GO_PLANE: delete((plane*)go); break;
case GO_BRICK: delete((Brick*)go); break;
case GO_LINE3D: delete((Line3D*)go); break;
case GO_LABEL: delete((Label*)go); break;
case GO_MLABEL: delete((mLabel*)go); break;
case GO_SEGMENT: delete((segment*)go); break;
case GO_POLYGON:
case GO_POLYLINE: delete((polyline*)go); break;
case GO_REGLINE: delete((RegLine*)go); break;
case GO_SDELLIPSE: delete((SDellipse*)go); break;
case GO_ELLIPSE:
case GO_ROUNDREC:
case GO_RECTANGLE: delete((rectangle*)go); break;
case GO_DRAGHANDLE: delete((dragHandle*)go); break;
case GO_DRAGRECT: delete((dragRect*)go); break;
case GO_DRAG3D: delete((Drag3D*)go); break;
case GO_FRAMERECT: delete((FrmRect*)go); break;
case GO_PLOT: delete((Plot*)go); break;
case GO_BARCHART:
case GO_PLOTSCATT: delete((PlotScatt*)go); break;
case GO_REGRESSION: delete((Regression*)go); break;
case GO_BUBBLEPLOT: delete((BubblePlot*)go); break;
case GO_BOXPLOT: delete((BoxPlot*)go); break;
case GO_DENSDISP: delete((DensDisp*)go); break;
case GO_STACKBAR:
case GO_WATERFALL:
case GO_STACKPG: delete((StackBar*)go); break;
case GO_POLARPLOT: delete((PolarPlot*)go); break;
case GO_RINGCHART:
case GO_PIECHART: delete((PieChart*)go); break;
case GO_GROUP:
case GO_STARCHART: delete((GoGroup*)go); break;
case GO_SCATT3D: delete((Scatt3D*)go); break;
case GO_PLOT3D: delete((Plot3D*)go); break;
case GO_PAGE:
case GO_GRAPH: delete((Graph*)go); break;
case GO_SVGOPTIONS: delete((svgOptions*)go); break;
case GO_DROPL3D: delete((DropLine3D*)go); break;
case GO_ARROW3D: delete((Arrow3D*)go); break;
case GO_LIMITS: delete((Limits*)go); break;
case GO_GRIDRADIAL: delete((GridRadial*)go); break;
case GO_DEFRW: delete((DefsRW*)go); break;
case GO_PLANE3D: delete((Plane3D*)go); break;
case GO_RIBBON: delete((Ribbon*)go); break;
case GO_FUNCTION: delete((Function*)go); break;
case GO_FITFUNC: delete((FitFunc*)go); break;
case GO_LEGITEM: delete((LegItem*)go); break;
case GO_LEGEND: delete((Legend*)go); break;
case GO_OBJTREE: delete((ObjTree*)go); break;
case GO_FREQDIST: delete((FreqDist*)go); break;
case GO_GRID3D: delete((Grid3D*)go); break;
case GO_FUNC3D: delete((Func3D*)go); break;
case GO_XYSTAT: delete((xyStat*)go); break;
default:
sprintf(TmpTxt, "Cannot delete Object\nwith Id %ld", go->Id);
ErrorBox(TmpTxt);
//we do not delete the object, probably we recover
}
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//Delete a graphic object from a list
bool DeleteGOL(GraphObj ***gol, long n, GraphObj *go, anyOutput *o)
{
long i;
int c;
GraphObj **g, *p;
if(!gol || !(*gol) || !go || !n) return false;
for (i = 0, c = 0, g = *gol; i < n; i++, g++) {
if(*g) {
c++;
if(*g == go) {
p = (*g)->parent;
if(o) o->HideMark();
Undo.DeleteGO(g, 0L, o);
if(c == 1) {
for (g++, i++ ;i < n; i++, g++) {
if(*g) return true;
}
if(p) Undo.DropMemory(p, (void**) gol, UNDO_CONTINUE);
}
return true;
}
}
}
return false;
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//backup file before writing a new one
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
bool BackupFile(char *FileName)
{
int i;
FILE *TheFile;
char TmpFileName[512], Name[512], ext[6];
//no backup necessary if file does not exist
if(!(FileExist(FileName))) return true;
strcpy(Name, FileName);
i = strlen(Name)-1;
if(Name[--i] == '.') Name[i] = 0;
else if(Name[--i] == '.') Name[i] = 0;
else if(Name[--i] == '.') Name[i] = 0;
else return false;
i = 1;
do {
sprintf(ext, ".%03d", i);
sprintf(TmpFileName, "%s%s", Name, ext);
if((TheFile = fopen(TmpFileName, "r"))) fclose(TheFile);
i++;
} while (i < 999 && TheFile);
if(i >= 999) { //too many backups exist already
ErrorBox("Too many backup\files exist already.");
return false;
}
if(-1 == rename(FileName, TmpFileName)) {
ErrorBox("Error accessing file.");
return false;
}
return true;
}
bool IsRlpFile(char *FileName)
{
FILE *TheFile;
char Line[10];
bool bRet = false;
if(0L ==(TheFile = fopen(FileName, "r"))) return false;
fread(Line, 1, 8, TheFile);
Line[5] = 0;
if(0 == strcmp(Line, ";RLP "))bRet = true;
fclose(TheFile);
return bRet;
}
bool IsXmlFile(char *FileName)
{
FILE *TheFile;
char Line[10];
bool bRet = false;
if(0L ==(TheFile = fopen(FileName, "r"))) return false;
fread(Line, 1, 8, TheFile);
Line[6] = 0;
if(0 == strcmp(Line, "<?xml "))bRet = true;
fclose(TheFile);
return bRet;
}
bool FileExist(char *FileName)
{
FILE *TheFile;
if(0L ==(TheFile = fopen(FileName, "r"))) return false;
fclose(TheFile);
return true;
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//check Object for certain properties
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
bool IsPlot3D(GraphObj *g)
{
if(g && (g->Id == GO_PLOT3D || g->Id == GO_FUNC3D)) return true;
return false;
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//duplicate a block of memory
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
void *memdup(void *ptr, int cb_old, int cb_new)
{
void *p;
if(cb_new > cb_old) {
if((p = calloc(cb_new, 1)) && ptr) memcpy(p, ptr, cb_old);
}
else {
if((p = malloc(cb_old)) && ptr) memcpy(p, ptr, cb_old);
}
return p;
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//calculate angle from sin(angle)
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
double trig2deg(double si, double csi)
{
double ang;
ang = acos(csi);
if(si < 0.0) ang *= -1.0;
return floor(ang * 57.29577951 +0.5);
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//replace graphic object with new: typically used for undo
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
bool ReplaceGO(GraphObj **oldobj, GraphObj **newobj)
{
newobj[1]->parent = newobj[0]->parent;
newobj[1]->Command(CMD_SET_DATAOBJ, newobj[0]->data, 0L);
*oldobj = newobj[1];
newobj[0]->parent = 0L; //disable messaging
Undo.InvalidGO(newobj[0]);
DeleteGO(newobj[0]);
return true;
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//calculate a 'unique' hash value for a string
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
unsigned int HashValue(unsigned char *str)
{
unsigned int i = 0, ret=0;
if(!str) return 0;
do {
if(str[i] > 32) ret = ((str[i]-32) + (ret <<2));
i++;
}while(str[i]);
if(i < 4) memcpy(&ret, str, i);
return ret;
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//compare data structures: return true if changed or save undo info
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
bool cmpLineDEF(LineDEF *l1, LineDEF *l2)
{
if(!l1 || !l2 || l1 == l2) return false; //oh, oh !
if(l1->width != l2->width) return true;
if(l1->patlength != l2->patlength) return true;
if(l1->color != l2->color) return true;
if(l1->pattern != l2->pattern) return true;
return false;
}
bool cmpFillDEF(FillDEF *f1, FillDEF *f2)
{
if(!f1 || !f2 || f1 == f2) return false; //oh, oh!
if(f1->type != f2->type || f1->color != f2->color ||
f1->scale != f2->scale || f1->color2 != f2->color2) return true;
//the hatch line is subject to a separate call to cmpLineDEF
return false;
}
bool cmpAxisDEF(AxisDEF *a1, AxisDEF *a2)
{
int i;
if(!a1 || !a2 || a1 == a2) return false; //oh, oh!
if(a1->flags != a2->flags || a1->min != a2->min || a1->max != a2->max ||
a1->loc[0].fx != a2->loc[0].fx || a1->loc[0].fy != a2->loc[0].fy ||
a1->loc[0].fz != a2->loc[0].fz || a1->loc[1].fx != a2->loc[1].fx ||
a1->loc[1].fy != a2->loc[1].fy || a1->loc[1].fz != a2->loc[1].fz ||
a1->Start != a2->Start || a1->Step != a2->Step || a1->Radius != a2->Radius ||
a1->Center.fx != a2->Center.fx || a1->Center.fy != a2->Center.fy ||
a1->nBreaks != a2->nBreaks) return true;
for(i = 0; i < a1->nBreaks; i++) {
if(a1->breaks[i].fx != a2->breaks[i].fx ||
a1->breaks[i].fy != a2->breaks[i].fy) return true;
}
return false;
}
bool cmpTextDEF(TextDEF *t1, TextDEF *t2)
{
if(!t1 || !t2) return false;
if(t1->ColTxt != t2->ColTxt || t1->ColBg != t2->ColBg || t1->fSize != t2->fSize ||
t1->RotBL != t2->RotBL || t1->RotCHAR != t2->RotCHAR || t1->iSize != t2->iSize ||
t1->Align != t2->Align || t1->Mode != t2->Mode || t1->Style != t2->Style ||
t1->Font != t2->Font) return true;
if((!(t1->text) && (t2->text)) || (!(t2->text) && (t1->text))) return true;
if(t1->text && t2->text && strcmp(t1->text, t2->text)) return true;
return false;
}
// Dialog Undo utilitites
DWORD CheckNewFloat(double *loc, double old_v, double new_v, GraphObj *par, DWORD flags)
{
if(loc && old_v != new_v) {
Undo.ValFloat(par, loc, flags);
*loc = new_v; return (flags | UNDO_CONTINUE);
}
return flags;
}
DWORD CheckNewInt(int *loc, int old_v, int new_v, GraphObj *par, DWORD flags)
{
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -