#include "PlotLib.h" Plot::Plot(): mode(PLOT_AA), bgcol(0xffffff,0), framecol(0xffffff,0), fontcol(0x0,0), axiscol(0x0,0), margin(10) { f=StdFont(); fi=f.Info(); marginB=margin+fi.GetHeight(); marginT=margin+fi.GetHeight()*1.5; } Plot& Plot::SetLimits(double x_min,double x_max,double y_min,double y_max){ g=Rectf(x_min,y_min,x_max,y_max); spaceH=margin+StrWidth("-99"); marginL=max(spaceH,StrWidth("×100")+margin); marginR=margin+spaceH/2+StrWidth("×100"); return *this; } Rectf Plot::BoundingBox(bool visibleonly){ Rectf b=Null; for(int i = 0; i < data.GetCount(); i++){ if(!visibleonly||data[i].visible){ Rectf& bb(data[i].BB); if(bb.IsNullInstance()||bb.Width()==0||bb.Height()==0){data[i].RefreshBB();} b.Union(bb); } } return b; } Plot& Plot::SetPlotSize(const Size& sz){ p=size=sz; p.Deflate(marginL,marginT,marginR,marginB); return *this; } bool Plot::CheckRange()const{ return ((g.Width()!=0)&&(g.Height()!=0)); } Pointf Plot::ImgToPlot(const Pointf& X)const{ Pointf pf=X; pf.Offset(-p.left,-p.top); return G(pf); } Rectf Plot::ImgToPlot(const Rectf& X)const{ return G(X.Offseted(-p.TopLeft())); } Pointf Plot::PlotToImg(const Pointf& X)const{ Pointf pf=X; pf=S(X); pf.Offset(p.left,p.top); return pf; } Rectf Plot::PlotToImg(const Rectf& X)const{ return S(X.Offseted(p.TopLeft())); } String Plot::ImgToPlotFormatted(const Point& X)const{ Pointf p=ImgToPlot(X); return String("[").Cat()<2)&(s<=5)){s=5;} else if((s>1)&(s<=2)){s=2;} else if((s>5)&(s<=10)){s=1;e++;} else {s=1;} } bool Plot::Axes(Painter& sw){ String str="×10"; int fh=f.GetHeight(); int e; double d,s; //Ticks X s=g.Width()/p.Width()*spaceH; //step based on axis length and spacing NormalizeStep(s,e); // makes step s 1,2 or 5; e is order of magnitude if(fabs(log10(fabs(g.left-g.right))-e)>16){ //TODO: find correct check g.SetSize(0,0); CheckRange(); return false; } sx=ipow10(-e); d=s*ipow10(e); //full value of step for(double x=ceil(g.left/d)*s; x<=g.right*sx; x+=s){TickH(x,e,sw);} //Scale X sw.DrawText(p.right+spaceH/2,p.bottom+6,str,f,fontcol); sw.DrawText(p.right+spaceH/2+StrWidth(str)-2,p.bottom+4,IntStr(e),f.Height(fh*0.6),fontcol); f.Height(fh); //Ticks Y s=g.Height()/p.Height()*fh*2; NormalizeStep(s,e); if(fabs(log10(fabs(g.top-g.bottom))-e)>16){ //TODO: find correct check g.SetSize(0,0); CheckRange(); return false; } sy=ipow10(-e); d=s*ipow10(e); for(double y=ceil(g.top/d)*s; y<=g.bottom*sy; y+=s){TickV(y,e,sw);} //Scale y sw.DrawText(5,margin,str,f,fontcol); sw.DrawText(5+StrWidth(str)-2,margin-2,IntStr(e),f.Height(fh*0.6),fontcol); f.Height(fh); //Frame Rect t=p.Inflated(1); sw.DrawRect(t.left,t.bottom,p.Width()+5,-1,axiscol); sw.DrawRect(t.left,t.bottom,1,-p.Height()-5,axiscol); sw.DrawLine(t.left+p.Width()+6,p.bottom,t.left+p.Width()+2,p.bottom+4,1,axiscol); sw.DrawLine(t.left+p.Width()+6,p.bottom,t.left+p.Width()+2,p.bottom-3,1,axiscol); sw.DrawLine(p.left-1,p.bottom-p.Height()-4,p.left+3,p.bottom-p.Height(),1,axiscol); sw.DrawLine(p.left,p.bottom-p.Height()-4,p.left-4,p.bottom-p.Height(),1,axiscol); return true; } void Plot::PaintData(const PlotData& data,Painter& sw){ if(data.visible&&data.GetCount()>=2){ sw.Move(S(data[0])); for(int i=1;iGetSize().cx>0&&data.symbol->GetSize().cy>0){ for(int i = 0; i < data.GetCount(); i++){ if(g.Contains(data[i])){data.symbol->Paint(sw,S(data[i]));} } } } } int Plot::LineClip(double& x1, double& y1, double& x2, double& y2)const{ int r=0; if(y1>g.bottom){ if(y2>g.bottom) return -1; //no intersect x1=(x2-x1)*(g.bottom-y1)/(y2-y1)+x1; y1=g.bottom; r=1; // 1st endpoint below viewport }else if(y1g.bottom){ x2=(x2-x1)*(g.bottom-y1)/(y2-y1)+x1; y2=g.bottom; r|=2; // 2nd endpoint below viewport }else if(y2g.right){ y2=(y2-y1)*(g.right-x1)/(x2-x1)+y1; x1=g.left; x2=g.right; return 3; // both endpoints outside } x1=g.left; return r|1; // 1st endpoint outside }else if(x1>g.right){ if(x2>g.right) return -1; //no intersect y1=(y2-y1)*(g.right-x1)/(x2-x1)+y1; if(x2g.right){ y2=(y2-y1)*(g.right-x1)/(x2-x1)+y1; x2=g.right; return r|2; // 2nd endpoint outside } return r; //depends on data gathered during clipping } //#include Image Plot::GetImage(){ ImageBuffer ib(size); BufferPainter bp(ib, mode); bp.Clear(framecol); bp.DrawRect(p,bgcol); if(!Axes(bp)){LOG("Axes failed");return Image();} // something is wrong with limits, let user deal with it ;-) bp.Offset(p.TopLeft()); for(int i=0; iGetHashValue():(unsigned)0); } return hash; }