📄 plotobs.cpp
字号:
//PlotObs.cpp, Copyright (c) 2001, 2002, 2003, 2004, 2005 R.Lackner
//
// This file is part of RLPlot.
//
// RLPlot is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation; either version 2 of the License, or
// (at your option) any later version.
//
// RLPlot is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with RLPlot; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
//
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// This modules contains code for the differnt Plot objects. Plots are
// graphic objects containing more objects, which represent the data.
// Several Plots may be contained in a Graph: Plots are the different layers
// of a Graph.
// Most part of this module has been moved here from rlplot.cpp of
// earlier versions.
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
#include "rlplot.h"
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include <string.h>
extern char TmpTxt[];
extern Default defs;
extern int cPlots;
extern GraphObj *CurrGO, *TrackGO; //Selected Graphic Objects
extern Axis **CurrAxes; //axes of current graph
extern UndoObj Undo;
int AxisTempl3D = 0;
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Plot::Plot(GraphObj *par, DataObj *d):GraphObj(par, d)
{
Id = GO_PLOT;
Bounds.Xmin = Bounds.Ymin = HUGE_VAL; Bounds.Xmax = Bounds.Ymax = -HUGE_VAL;
sprintf(TmpTxt, "Plot %d", ++cPlots);
name = strdup(TmpTxt);
use_xaxis = use_yaxis = 0;
hidden = 0;
}
double
Plot::GetSize(int select)
{
switch(select){
case SIZE_MINE: return 0.0;
//The Bounds values must be returned by every plot:
// they are necessary for scaling !
case SIZE_BOUNDS_XMIN:
return parent ? parent->GetSize(SIZE_BOUNDS_XMIN) : Bounds.Xmin;
case SIZE_BOUNDS_XMAX:
return parent ? parent->GetSize(SIZE_BOUNDS_XMAX) : Bounds.Xmax;
case SIZE_BOUNDS_YMIN:
return parent ? parent->GetSize(SIZE_BOUNDS_YMIN) : Bounds.Ymin;
case SIZE_BOUNDS_YMAX:
return parent ? parent->GetSize(SIZE_BOUNDS_YMAX) : Bounds.Ymax;
case SIZE_BARMINX:
case SIZE_BARMINY:
return 1.0f;
default:
if(parent) return parent->GetSize(select);
else return defs.GetSize(select);
}
}
DWORD
Plot::GetColor(int select)
{
if(parent) return parent->GetColor(select);
else return defs.Color(select);
}
void
Plot::CheckBounds(double x, double y)
{
if(x < Bounds.Xmin) Bounds.Xmin = x; if(x > Bounds.Xmax) Bounds.Xmax = x;
if(y < Bounds.Ymin) Bounds.Ymin = y; if(y > Bounds.Ymax) Bounds.Ymax = y;
}
bool
Plot::UseAxis(int idx)
{
double dx, dy;
if(CurrAxes && CurrAxes[idx]) {
dx = fabs(CurrAxes[idx]->GetSize(SIZE_XPOS+1) -
CurrAxes[idx]->GetSize(SIZE_XPOS));
dy = fabs(CurrAxes[idx]->GetSize(SIZE_YPOS+1) -
CurrAxes[idx]->GetSize(SIZE_YPOS));
if(dx > dy && idx != use_xaxis) {
Undo.ValInt(parent, &use_xaxis, 0L);
use_xaxis = idx; return true;
}
else if(idx != use_yaxis) {
Undo.ValInt(parent, &use_yaxis, 0L);
use_yaxis = idx; return true;
}
}
return false;
}
void
Plot::ApplyAxes(anyOutput *o)
{
AxisDEF x_axis, y_axis;
double dsp;
fRECT CurrRect;
if(!o || !CurrAxes || !parent) return;
memcpy(&x_axis, &o->xAxis, sizeof(AxisDEF));
memcpy(&y_axis, &o->yAxis, sizeof(AxisDEF));
CurrRect.Xmin = (dsp = parent->GetSize(SIZE_GRECT_LEFT)) +
parent->GetSize(SIZE_DRECT_LEFT);
CurrRect.Xmax = dsp + parent->GetSize(SIZE_DRECT_RIGHT);
if(use_xaxis && CurrAxes[use_xaxis]) {
memcpy(&x_axis, CurrAxes[use_xaxis]->axis, sizeof(AxisDEF));
if(x_axis.flags & AXIS_DEFRECT) {
x_axis.loc[0].fx += dsp; x_axis.loc[1].fx += dsp;
}
}
else use_xaxis = 0;
CurrRect.Ymin = (dsp = parent->GetSize(SIZE_GRECT_TOP)) +
parent->GetSize(SIZE_DRECT_BOTTOM);
CurrRect.Ymax = dsp + parent->GetSize(SIZE_DRECT_TOP);
if(use_yaxis && CurrAxes[use_yaxis]) {
memcpy(&y_axis, CurrAxes[use_yaxis]->axis, sizeof(AxisDEF));
if(y_axis.flags & AXIS_DEFRECT) {
y_axis.loc[0].fy += dsp; y_axis.loc[1].fy += dsp;
}
}
else use_yaxis = 0;
o->SetRect(CurrRect, o->units, &x_axis, &y_axis);
}
void
Plot::CheckBounds3D(double x, double y, double z)
{
if(x < xBounds.fx) xBounds.fx = x; if(x > xBounds.fy) xBounds.fy = x;
if(y < yBounds.fx) yBounds.fx = y; if(y > yBounds.fy) yBounds.fy = y;
if(z < zBounds.fx) zBounds.fx = z; if(z > zBounds.fy) zBounds.fy = z;
CheckBounds(x, y);
}
bool
Plot::SavVarObs(GraphObj **gol, long ngo, DWORD flags)
{
int i;
void *ptr;
if(!gol || !ngo) return false;
SavVarInit(150 * ngo);
for(i = 0; i < ngo; i++)
if(gol[i]) gol[i]->FileIO(SAVE_VARS);
ptr = SavVarFetch();
Undo.SavVarBlock(this, &ptr, flags);
return true;
}
DataObj *
Plot::CreaCumData(char *xr, char *yr, int mode, double base)
{
char **yranges;
int i, j, nc, nr, ir, ic;
double value, old_val;
DataObj *CumData = 0L;
AccRange *ax = 0L, *ay = 0L;
if(!xr || !yr || !mode || !data) return 0L;
if(!(CumData = new DataObj()))return 0L;
if(!(ax = new AccRange(xr))) {
delete CumData; return 0L;
}
nr = ax->CountItems();
if(!(yranges = split(yr, '&', &nc))){
delete CumData; delete ax; return 0L;
}
if(CumData->Init(mode == 1 || mode == 2 ? nr : nr * 2, nc+2)){
// set x values as first column
for(i = 0, ax->GetFirst(&ic, &ir); ax->GetNext(&ic, &ir); i++) {
if(data->GetValue(ir, ic, &value)) CumData->SetValue(i, 0, value);
CumData->SetValue(i, 1, base);
}
if(mode == 3 || mode == 4) for(i = 1; i <= nr; i++) { //complete polygon data
if(CumData->GetValue(nr-i, 0, &value)) CumData->SetValue(i-1+nr, 0, value);
}
//process all y-ranges
for (j = 2; j <= (nc+1); j++) if(ay = new AccRange(yranges[j-2])){
for(i = 0; i < nr; i++) {
if(CumData->GetValue(i, j-1, &value)) CumData->SetValue(i, j, value);
}
for(i = 0, ay->GetFirst(&ic, &ir); ay->GetNext(&ic, &ir) && i < nr; i++) {
if(data->GetValue(ir, ic, &value) && CumData->GetValue(i, j, &old_val)){
switch (mode) {
case 1: case 3: value += old_val; break;
case 2: case 4: value = old_val -value; break;
}
CumData->SetValue(i, j, value);
}
}
if(mode == 3 || mode == 4) for(i = 1; i <= nr; i++) {
//complete polygon data
if(CumData->GetValue(nr-i, j-1, &value)) CumData->SetValue(i-1+nr, j, value);
}
delete ay; ay = 0L;
}
}
for(i = 0; i < nc; i++) if(yranges[i]) free(yranges[i]);
if(ax) delete ax; if(ay) delete ay;
free(yranges);
return CumData;
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// PlotScatt handles most XY-Plots: its a Plot-Class
PlotScatt::PlotScatt(GraphObj *par, DataObj *d, DWORD presel):Plot(par, d)
{
FileIO(INIT_VARS);
DefSel = presel;
Id = GO_PLOTSCATT;
if (!d) {
if(parent && parent->Command(CMD_DELOBJ, this, NULL)) return;
ErrorBox("Attempt to create plot\nwithout any data.");
return;
}
}
PlotScatt::PlotScatt(GraphObj *par, DataObj *d, int cBars, Bar **bars):Plot(par, d)
{
int i;
FileIO(INIT_VARS);
if(cBars && bars) {
if((Bars = (Bar**)calloc(cBars, sizeof(Bar*)))) {
nPoints = cBars;
for(i = 0; i < cBars; i++) {
if((Bars[i] = bars[i])) Bars[i]->parent = this;
bars[i] = 0L;
}
}
}
Id = GO_PLOTSCATT;
}
PlotScatt::PlotScatt(GraphObj *par, DataObj *d, int nPts, Symbol **sym, DataLine *lin):
Plot(par, d)
{
int i;
FileIO(INIT_VARS);
nPoints = nPts;
if(Symbols = sym) for(i = 0; i < nPts; i++) if(Symbols[i]) Symbols[i]->parent = this;
if(TheLine = lin) TheLine->parent = this;
Id = GO_PLOTSCATT;
}
PlotScatt::PlotScatt(int src):Plot(0L, 0L)
{
FileIO(INIT_VARS);
if(src == FILE_READ) {
FileIO(FILE_READ);
}
}
PlotScatt::~PlotScatt()
{
ForEach(FE_FLUSH, 0L, 0L);
if(name) free(name); name=0L;
Undo.InvalidGO(this);
}
double
PlotScatt::GetSize(int select)
{
int i;
double ft1, ft2, d;
switch(select){
case SIZE_BARMINX:
if(BarDist.fx >= 0.0001) return BarDist.fx;
if((!Bars) || (nPoints < 2)) return BarDist.fx = 1.0;
ft1 = -HUGE_VAL; ft2 = HUGE_VAL; BarDist.fx= HUGE_VAL;
for(i = 0; i < nPoints; i++) {
if(Bars[i]) {
ft2 = Bars[i]->GetSize(SIZE_XPOS);
d = fabs(ft2-ft1);
if(d != 0.0 && d < BarDist.fx) BarDist.fx = d;
}
ft1 = ft2;
}
return BarDist.fx = BarDist.fx > 0.0001 && BarDist.fx != HUGE_VAL ? BarDist.fx : 1.0;
case SIZE_BARMINY:
if(BarDist.fy >= 0.0001) return BarDist.fy;
if((!Bars) || (nPoints < 2)) return BarDist.fy = 1.0;
ft1 = -HUGE_VAL; ft2 = HUGE_VAL; BarDist.fy= HUGE_VAL;
for(i = 0; i < nPoints; i++) {
if(Bars[i]) {
ft2 = Bars[i]->GetSize(SIZE_YPOS);
d = fabs(ft2-ft1);
if(d != 0.0 && d < BarDist.fy) BarDist.fy = d;
}
ft1 = ft2;
}
return BarDist.fy = BarDist.fy > 0.0001 && BarDist.fy != HUGE_VAL ? BarDist.fy : 1.0;
default:
return Plot::GetSize(select);
}
}
bool
PlotScatt::SetSize(int select, double value)
{
int i;
switch(select & 0xfff){
case SIZE_BARMINX:
BarDist.fx = value;
return true;
case SIZE_BARMINY:
BarDist.fy = value;
return true;
case SIZE_SYMBOL: case SIZE_SYM_LINE:
if(Symbols) for(i = 0; i < nPoints; i++)
if(Symbols[i]) Symbols[i]->SetSize(select, value);
return true;
case SIZE_WHISKER: case SIZE_WHISKER_LINE:
case SIZE_ERRBAR: case SIZE_ERRBAR_LINE:
if(Errors) for(i = 0; i < nPoints; i++)
if(Errors[i]) Errors[i]->SetSize(select, value);
return true;
case SIZE_BAR_LINE: case SIZE_BAR: case SIZE_XBASE: case SIZE_YBASE:
if(Bars) for(i = 0; i < nPoints; i++)
if(Bars[i]) Bars[i]->SetSize(select, value);
return true;
case SIZE_LB_XDIST: case SIZE_LB_YDIST:
if(Labels) for(i = 0; i < nPoints; i++)
if(Labels[i]) Labels[i]->SetSize(select, value);
return true;
case SIZE_ARROW_LINE: case SIZE_ARROW_CAPWIDTH: case SIZE_ARROW_CAPLENGTH:
if(Arrows) for(i = 0; i < nPoints; i++)
if(Arrows[i]) Arrows[i]->SetSize(select, value);
return true;
}
return false;
}
bool
PlotScatt::SetColor(int select, DWORD col)
{
int i;
GraphObj **go = 0L;
switch(select) {
case COL_SYM_LINE:
case COL_SYM_FILL: go = (GraphObj**)Symbols; break;
case COL_WHISKER:
case COL_ERROR_LINE: go = (GraphObj**)Errors; break;
case COL_BAR_LINE:
case COL_BAR_FILL: go = (GraphObj**)Bars; break;
case COL_ARROW: go = (GraphObj**)Arrows; break;
default: return false;
}
if(go) for(i = 0; i < nPoints; i++)
if(go[i]) go[i]->SetColor(select, col);
return true;
}
void
PlotScatt::DoPlot(anyOutput *o)
{
if(!parent) return;
parent->Command(CMD_REG_AXISPLOT, (void*)this, o);
if(use_xaxis || use_yaxis) {
ApplyAxes(o);
ForEach(FE_PLOT, 0L, o);
parent->Command(CMD_AXIS, 0L, o);
}
else {
ForEach(FE_PLOT, 0L, o);
}
dirty = false;
}
bool
PlotScatt::Command(int cmd, void *tmpl, anyOutput *o)
{
int i;
switch (cmd) {
case CMD_MOUSE_EVENT:
if(hidden) return false;
if(!CurrGO && ((MouseEvent*)tmpl)->Action == MOUSE_LBUP)
return ForEach(cmd, tmpl, o);
return false;
case CMD_LEGEND:
if(((GraphObj*)tmpl)->Id != GO_LEGEND) return false;
if(Bars) for (i = 0; i < nPoints; i++)
if(Bars[i]) Bars[i]->Command(cmd, tmpl, o);
if(Symbols) {
if(TheLine && TheLine->Id == GO_DATALINE) {
for (i = 0; i < nPoints && i < 100; i++)
if(Symbols[i]) ((Legend*)tmpl)->HasSym(&TheLine->LineDef, Symbols[i]);
}
else {
for (i = 0; i < nPoints && i < 100; i++)
if(Symbols[i]) ((Legend*)tmpl)->HasSym(0L, Symbols[i]);
}
if(TheLine && TheLine->Id == GO_DATAPOLYGON) TheLine->Command(cmd, tmpl, o);
}
else if(TheLine) TheLine->Command(cmd, tmpl, o);
break;
case CMD_MRK_DIRTY:
dirty = true;
case CMD_SETSCROLL: case CMD_REDRAW:
if(parent) return parent->Command(cmd, tmpl, o);
return false;
case CMD_USEAXIS:
return UseAxis(*((int*)tmpl));
case CMD_FLUSH:
return ForEach(FE_FLUSH, 0L, 0L);
case CMD_AUTOSCALE:
if(hidden) return false;
if(dirty){
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -