📄 rlplot.cpp
字号:
DataLine::Command(int cmd, void *tmpl, anyOutput *o){ MouseEvent *mev; bool bFound = false; POINT p1; int i; switch (cmd) { case CMD_MOUSE_EVENT: mev = (MouseEvent *) tmpl; switch (mev->Action) { case MOUSE_LBUP: if(!IsInRect(&rDims, p1.x= mev->x, p1.y= mev->y) || CurrGO || !o || nPntSet <1) return false; if(isPolygon && IsInPolygon(&p1, pts, cp)) bFound = true; if(bFound || IsCloseToPL(p1,pts,cp)) return o->ShowMark(this, MRK_GODRAW); } break; case CMD_SET_DATAOBJ: Id = isPolygon ? GO_DATAPOLYGON : GO_DATALINE; data = (DataObj*)tmpl; return true;
case CMD_MRK_DIRTY:
dirty= true;
case CMD_REDRAW:
if(parent) return parent->Command(cmd, tmpl, 0L);
return false;
case CMD_LEGEND: if(tmpl && ((GraphObj*)tmpl)->Id == GO_LEGEND) { if(Id == GO_DATALINE) ((Legend*)tmpl)->HasFill(&LineDef, 0L); } break; case CMD_SET_LINE: if(tmpl) memcpy(&LineDef, tmpl, sizeof(LineDEF)); return true; case CMD_UPDATE:
Undo.DataMem(this, (void**)&Values, nPnt * sizeof(lfPOINT), &nPnt, UNDO_CONTINUE);
Undo.ValLong(this, &nPntSet, UNDO_CONTINUE);
SetValues(); return true; case CMD_AUTOSCALE: if(nPntSet < 1 || !Values) return false; if(parent && parent->Id >= GO_PLOT && parent->Id < GO_GRAPH) { if(dirty) { min.fx = max.fx = Values[0].fx; min.fy = max.fy = Values[0].fy; for (i = 1; i <= nPntSet; i++){ min.fx = Values[i].fx < min.fx ? Values[i].fx : min.fx; max.fx = Values[i].fx > max.fx ? Values[i].fx : max.fx; min.fy = Values[i].fy < min.fy ? Values[i].fy : min.fy; max.fy = Values[i].fy > max.fy ? Values[i].fy : max.fy; } } ((Plot*)parent)->CheckBounds(min.fx, min.fy); ((Plot*)parent)->CheckBounds(max.fx, max.fy); dirty = false; return true; } return false; } return false;}voidDataLine::SetValues(){ AccRange *rX, *rY1=0L, *rY2=0L; int i, j, k, l, m, n; double x, y; char *yref1 = 0L, *yref2 = 0L; lfPOINT *tmpValues = Values; if(!ssXref || !ssYref) return; if(!(yref1 = strdup(ssYref)))return; for(i = 0; yref1[i]; i++) { if(yref1[i] == ';') { yref1[i++] = 0; while(yref1[i] && yref1[i] < 33) i++; yref2 = strdup(yref1+i); } } nPnt = nPntSet = 0; min.fx = min.fy = HUGE_VAL; max.fx = max.fy = -HUGE_VAL; rX = new AccRange(ssXref); rY1 = new AccRange(yref1); if(!rX || !rY1){ if(yref1) free(yref1); if(yref2) free(yref2); if(rX) delete(rX); if(rY1) delete(rY1); return; } if(yref2 &&((nPnt = rX->CountItems()) == (rY1->CountItems()))) { if(!(Values = (lfPOINT *)realloc(Values, ((nPnt*2+2) * sizeof(lfPOINT))))) return; if(!(rY2 = new AccRange(yref2))) { if(yref1) free(yref1); if(yref2) free(yref2); if(rX) delete(rX); if(rY1) delete(rY1); return; } if(rX->GetFirst(&i, &j) && rY1->GetFirst(&k, &l) && rX->GetNext(&i, &j) && rY1->GetNext(&k, &l) && rY2->GetFirst(&m, &n) && rY2->GetNext(&m, &n)) do { if(data->GetValue(j, i, &x)){ if(data->GetValue(l, k, &y)){ Values[nPntSet].fx = x; Values[nPntSet++].fy = y; } if(data->GetValue(n, m, &y)){ Values[nPntSet].fx = x; Values[nPntSet++].fy = y; } } }while(rX->GetNext(&i, &j) && rY1->GetNext(&k, &l) && rY2->GetNext(&m, &n)); } else { if((nPnt = rX->CountItems()) != (rY1->CountItems())) return; if(!(Values = (lfPOINT *)realloc(Values, (nPnt+2) * sizeof(lfPOINT)))) return; if(rX->GetFirst(&i, &j) && rY1->GetFirst(&k, &l) && rX->GetNext(&i, &j) && rY1->GetNext(&k, &l)) do { if(data->GetValue(j, i, &x) && data->GetValue(l, k, &y)){ Values[nPntSet].fx = x; Values[nPntSet++].fy = y; } }while(rX->GetNext(&i, &j) && rY1->GetNext(&k, &l)); } nPnt = nPntSet; nPntSet--; dirty = true; Command(CMD_AUTOSCALE, 0L, 0L);
if(tmpValues && Values != tmpValues) Undo.InvalidGO(this); if(rX) delete(rX); if(rY1) delete(rY1); if(rY2) delete(rY2); if(yref1) free(yref1); if(yref2) free(yref2);}voidDataLine::LineData(lfPOINT *val, long nval){
lfPOINT *ov = Values;
if(!val || nval <2) return;
if(nval > nPnt && nPnt > 1 && Values){
if(!(Values = (lfPOINT *)realloc(Values, ((nval*2+2) * sizeof(lfPOINT))))) return;
if(ov != Values) Undo.InvalidGO(this);
} else if(!Undo.busy) Undo.DataMem(this, (void**)&Values, nPnt * sizeof(lfPOINT), &nPnt, UNDO_CONTINUE);
memcpy(Values, val, nval * sizeof(lfPOINT));
if(pts) free(pts); pts = 0L; dirty = true; free(val); nPnt = nval; nPntSet = nPnt-1;}
void
DataLine::DrawSpline(anyOutput *target)
{
int i, j, k, klo, khi, ptsize = 1000;
double *y2, min, max, x, y, h, b, a;
POINT pn;
lfPOINT *scvals;
if(!(y2 = (double*)malloc(sizeof(double)*(nPnt)))) return;
if(!(scvals = (lfPOINT*)malloc(sizeof(lfPOINT)*(nPnt)))){
free(y2);
return;
}
if((type & 0x0f) == 9 || (type & 0x0f) == 10) {
if((type & 0x0f) == 9) for(i = 0; i < nPnt; i++) {
scvals[i].fx = target->fx2fix(Values[i].fx);
scvals[i].fy = target->fy2fiy(Values[i].fy);
}
else for(i = 0; i < nPnt; i++) {
scvals[i].fy = target->fx2fix(Values[i].fx);
scvals[i].fx = target->fy2fiy(Values[i].fy);
}
SortFpArray(nPnt, scvals);
min = scvals[0].fx; max = scvals[nPnt-1].fx;
for(i = j = 0; i < (nPnt-1); i++, j++) {
y = scvals[i].fy; scvals[j].fx = scvals[i].fx;
for(k = 1; scvals[i+1].fx == scvals[i].fx; k++) {
y += scvals[i+1].fy; i++;
}
scvals[j].fy = y/((double)k);
}
if(scvals[i].fx > scvals[i-1].fx) {
scvals[j].fx = scvals[i].fx; scvals[j].fy = scvals[i].fy;
j++;
}
spline(scvals, j, y2);
h = scvals[1].fx - scvals[0].fx; // klo and khi bracket the input value of x
for(x = min, klo = 0, i = khi = 1; x < max && i < j; x += 1.0) {
while(x > scvals[i].fx) {
klo++; khi++; i++;
h = scvals[khi].fx - scvals[klo].fx;
}
a = (scvals[khi].fx - x) / h; b = (x - scvals[klo].fx) / h;
y = a * scvals[klo].fy + b * scvals[khi].fy + ((a*a*a - a) * y2[klo] + (b*b*b - b) * y2[khi]) * (h*h)/6.0;
if((type & 0x0f) == 9) {
pn.x = iround(x); pn.y = iround(y);
}
else {
pn.x = iround(y); pn.y = iround(x);
}
if(cp >= ptsize) {
ptsize += 1000;
pts = (POINT*)realloc(pts, sizeof(POINT)*ptsize);
}
AddToPolygon(&cp, pts, &pn);
}
}
free(y2); free(scvals);
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~// DataPolygon is a graphic object based on DataLineDataPolygon::DataPolygon(GraphObj *par, DataObj *d, char *xrange, char *yrange): DataLine(par, d, xrange, yrange){ lfPOINT *fp = Values; char *rx = ssXref; char *ry = ssYref; FileIO(INIT_VARS); Values = fp; //FileIO will just set Values to 0L ! ssXref = rx; ssYref = ry; Id = GO_DATAPOLYGON;}DataPolygon::DataPolygon(int src):DataLine(0L, 0){ FileIO(INIT_VARS); if(src == FILE_READ) { FileIO(FILE_READ); }}DataPolygon::~DataPolygon(){ if(Values)free(Values); Values =0L; if(pts) free (pts); pts = 0L; if(ssXref) free(ssXref); ssXref = 0L; if(ssYref) free(ssYref); ssYref = 0L; if(mo) DelBitmapClass(mo); mo = 0L; if(parent)parent->Command(CMD_MRK_DIRTY, 0L, 0L);}voidDataPolygon::DoPlot(anyOutput *target){ if(!Values || nPntSet < 2) return; if(mo) DelBitmapClass(mo); mo = 0L; DataLine::DoPlot(target); //no drawing but fill pts only target->SetLine(&LineDef); target->SetFill(&pgFill); target->oPolygon(pts, cp);}voidDataPolygon::DoMark(anyOutput *o, bool mark){ if(pts && cp && o){ if(mark){ memcpy(&mrc, &rDims, sizeof(RECT)); IncrementMinMaxRect(&mrc, 6 + o->un2ix(LineDef.width)); mo = GetRectBitmap(&mrc, o); InvertPolygon(pts, cp, &LineDef, &pgFill, &mrc, o, mark); } else RestoreRectBitmap(&mo, &mrc, o); }}boolDataPolygon::Command(int cmd, void *tmpl, anyOutput *o){ switch (cmd) { case CMD_PG_FILL: if(tmpl) { memcpy((void*)&pgFill, tmpl, sizeof(FillDEF)); if(pgFill.hatch) memcpy((void*)&pgFillLine, (void*)pgFill.hatch, sizeof(LineDEF)); pgFill.hatch = (LineDEF*)&pgFillLine; } return true; case CMD_LEGEND: if(tmpl && ((GraphObj*)tmpl)->Id == GO_LEGEND) { if(Id == GO_DATAPOLYGON) ((Legend*)tmpl)->HasFill(&LineDef, &pgFill); } break; default: return DataLine::Command(cmd, tmpl, o); } return false;}//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~// Calculate and display a regression line// Ref.: "Biometry" third edition 1995 (ed. R.R. Sokal and F.J. Rohlf),// W.H. Freeman and Company, New York; ISBN 0-7167-2411-1; pp. 451ffRegLine::RegLine(GraphObj *par, DataObj *d, lfPOINT *values, long n, int sel): GraphObj(par, d){ FileIO(INIT_VARS); type = sel; Id = GO_REGLINE; uclip.Xmin = uclip.Ymin = lim.Xmin = lim.Ymin = -1.0; uclip.Xmax = uclip.Ymax = lim.Xmax = lim.Ymax = 1.0; Recalc(values, n);}RegLine::RegLine(int src):GraphObj(0L, 0L){ FileIO(INIT_VARS); if(src == FILE_READ) FileIO(FILE_READ);}RegLine::~RegLine(){ if(pts) free(pts); pts = 0L; if(parent)parent->Command(CMD_MRK_DIRTY, 0L, 0L);}doubleRegLine::GetSize(int select){ double a, b; switch(select) { case SIZE_MX: return mx; case SIZE_MY: return my; case SIZE_A: case SIZE_B: switch(type & 0x07) { case 1: a = l2.fx; b = l2.fy; break; case 2: a = l3.fx; b = l3.fy; break; case 3: a = l4.fx; b = l4.fy; break; case 4: a = l5.fx; b = l5.fy; break; default: a = l1.fx; b = l1.fy; break; } if(select == SIZE_A) return a; else return b; } return 0.0;}voidRegLine::DoPlot(anyOutput *o){ int i; POINT pn, *tmppts; double x, x1, y, d, a, b; fRECT cliprc; bool dValid; switch (type & 0x70) { case 0x20: memcpy(&cliprc, &uclip, sizeof(fRECT)); break; case 0x10: if(parent) { cliprc.Xmin = parent->GetSize(SIZE_BOUNDS_LEFT); cliprc.Xmax = parent->GetSize(SIZE_BOUNDS_RIGHT); cliprc.Ymin = parent->GetSize(SIZE_BOUNDS_BOTTOM); cliprc.Ymax = parent->GetSize(SIZE_BOUNDS_TOP); break; } //no parent: use default default: memcpy(&cliprc, &lim, sizeof(fRECT)); break; } if(cliprc.Xmax < cliprc.Xmin) { x = cliprc.Xmax; cliprc.Xmax = cliprc.Xmin; cliprc.Xmin = x; } if(cliprc.Ymax < cliprc.Ymin) { y = cliprc.Ymax; cliprc.Ymax = cliprc.Ymin; cliprc.Ymin = y; } if(cliprc.Xmin == cliprc.Xmax || cliprc.Ymin == cliprc.Ymax) return; if(pts) free(pts); if(!(pts = (POINT *)malloc(sizeof(POINT)*200)))return; switch(type & 0x07) { case 1: a = l2.fx; b = l2.fy; break; case 2: a = l3.fx; b = l3.fy; break; case 3: a = l4.fx; b = l4.fy; break; case 4: a = l5.fx; b = l5.fy; break; default: a = l1.fx; b = l1.fy; break; } x = cliprc.Xmin; d = (cliprc.Xmax - cliprc.Xmin)/200.0; for (cp = i = 0; i <= 200; i++){ dValid = true; switch(type & 0x700) { case 0x100: //logarithmic x if(dValid = x > defs.min4log) x1 = log10(x); break; case 0x200: //reciprocal x if(dValid = fabs(x) > defs.min4log) x1 = 1.0/x; break; case 0x300: //square root x if(dValid = fabs(x) > defs.min4log) x1 = sqrt(x); break; default: x1 = x; break; //linear x } y = a + b*x1; if(dValid) switch(type & 0x7000) { case 0x1000: //logarithmic y y = pow(10.0, y); break; case 0x2000: //reciprocal y if(dValid = fabs(y) >0.0001) y = 1.0/y; break; case 0x3000: //square root y if(dValid = fabs(y) >0.0001) y = y*y; break; } if(dValid && y >= cliprc.Ymin && y <= cliprc.Ymax) { pn.x = o->fx2ix(x); pn.y = o->fy2iy(y); AddToPolygon(&cp, pts, &pn); } x += d; } if(cp < 2) return; o->SetLine(&LineDef); o->oPolyline(pts, cp); if(tmppts = (POINT*)realloc(pts, cp *sizeof(POINT))) pts = tmppts; SetMinMaxRect(&rDims, pts[0].x, pts[0].y, pts[1].x, pts[1].y); for(i = 2; i < cp; i++) UpdateMinMaxRect(&rDims, pts[i].x, pts[i].y); i = 2*o->un2ix(LineDef.width); //increase size of rectangle for marks IncrementMinMaxRect(&rDims, i);}voidRegLine::DoMark(anyOutput *o, bool mark){ if(pts && cp && o){ if(mark)InvertLine(pts, cp, &LineDef, &rDims, o, mark); else if(parent) parent->Command(CMD_REDRAW, 0L, o); }}boolRegLine::Command(int cmd, void *tmpl, anyOutput *o){ MouseEvent *mev; POINT p1; switch (cmd) { case CMD_MOUSE_EVENT: mev = (MouseEvent *) tmpl; switch (mev->Action) { case MOUSE_LBUP: if(!IsInRect(&rDims, p1.x= mev->x, p1.y= mev->y) || CurrGO || !o || nPoints <2) return false; if(IsCloseToPL(p1,pts,cp)) return o->ShowMark(CurrGO= this, MRK_GODRAW); } break; case CMD_SET_DATAOBJ: Id = GO_REGLINE; return true; case CMD_BOUNDS: if(tmpl) { memcpy(&lim, tmpl, sizeof(fRECT)); memcpy(&uclip, tmpl, sizeof(fRECT)); } return true; case CMD_AUTOSCALE: if(nPoints < 2) return false; if(parent && parent->Id >= GO_PLOT && parent->Id < GO_GRAPH) { ((Plot*)parent)->CheckBounds(lim.Xmin, lim.Ymin); ((Plot*)parent)->CheckBounds(lim.Xmax, lim.Ymax); return true; } return false; } return false;}voidRegLine::Recalc(lfPOINT *values, long n){ double sx, sy, dx, dy, sxy, sxx, syy; double a, b, k; long ic; sx = sy = 0.0; if((nPoints = n)<2) return; for(ic = 0; ic < n; ic++) { sx += values[ic].fx; sy += values[ic].fy; } mx = sx /((double)nPoints); my = sy/((double)nPoints); sxy = sxx = syy = 0.0; for(ic = 0; ic < n; ic++) { dx = mx - values[ic].fx; dy = my - values[ic].fy; sxx += (dx*dx); sy
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -