#include "Scatter.h" #define IMAGECLASS ChartImg #define IMAGEFILE #include Scatter::MouseBehaviour defaultMouse[] = { {false, false, false, true , false, 0, false, Scatter::SHOW_INFO}, {false, false, false, false, false, 0, true , Scatter::CONTEXT_MENU}, {false, false, false, false, true , 0, false, Scatter::SCROLL}, {false, false, false, false, false, 1, false, Scatter::ZOOM_H_RED}, {false, false, false, false, false, 1, false, Scatter::ZOOM_V_RED}, {false, false, false, false, false,-1, false, Scatter::ZOOM_H_ENL}, {false, false, false, false, false,-1, false, Scatter::ZOOM_V_ENL}, {false, false, false, false, false, 0, false, Scatter::NO_ACTION}}; Scatter& Scatter::SetColor(const class::Color& _color) { graphColor=_color; return *this; } Scatter& Scatter::SetTitle(const String& _title) { title=_title; return *this; } Scatter& Scatter::SetTitleFont(const Font& fontTitle) { titleFont=fontTitle; return *this; } Scatter& Scatter::SetTitleColor(const class::Color& colorTitle) { titleColor=colorTitle; return *this; } void Scatter::SetLabels(const WString& _xLabel, const WString& _yLabel, const WString& _yLabel2) { xLabel=_xLabel; yLabel=_yLabel; yLabel2=_yLabel2; } Scatter& Scatter::SetLabelX(const WString& _xLabel) { xLabel=_xLabel; return *this; } Scatter& Scatter::SetLabelY(const WString& _yLabel) { yLabel=_yLabel; return *this; } Scatter& Scatter::SetLabelY2(const WString& _yLabel) { yLabel2=_yLabel; return *this; } Scatter& Scatter::SetLabelsFont(const Font& fontLabels) { labelsFont=fontLabels; return *this; } Scatter& Scatter::SetLabelsColor(const class::Color& colorLabels) { labelsColor=colorLabels; return *this; } Scatter& Scatter::SetPlotAreaPoz(const int& poz_x, const int& poz_y) { px=poz_x; py=poz_y; return *this; } Scatter& Scatter::H_Border(const int& poz_x) { if(poz_x>=0) px=poz_x; return *this; } Scatter& Scatter::V_Border(const int& poz_y) { if(poz_y>=0) py=poz_y; return *this; } Scatter& Scatter::SetPlotAreaColor(const class::Color& p_a_color) { plotAreaColor=p_a_color; return *this; } Scatter& Scatter::SetAxisColor(const class::Color& axis_color) { axisColor=axis_color; return *this; } Scatter& Scatter::SetAxisWidth(const int& axis_width) { axisWidth=axis_width; return *this; } Scatter& Scatter::SetGridColor(const class::Color& grid_color) { gridColor=grid_color; return *this; } Scatter& Scatter::SetGridWidth(const int& grid_width) { gridWidth=grid_width; return *this; } Scatter& Scatter::ShowHGrid(const bool& show) { drawHGrid=show; return *this; } Scatter& Scatter::ShowVGrid(const bool& show) { drawVGrid=show; return *this; } Scatter& Scatter::ShowLegend(const bool& show) { showLegend=show; return *this; } Scatter& Scatter::SetLegendWeight(const int& weight) { legendWeight=weight; return *this; } Scatter& Scatter::SetAntialiasing(const bool& aa) { antialiasing=aa; return *this; } Scatter &Scatter::SetDrawXReticle(bool set) { drawXReticle = set; return *this; } Scatter &Scatter::SetDrawYReticle(bool set) { drawYReticle = set; return *this; } Scatter &Scatter::SetDrawY2Reticle(bool set) { drawY2Reticle = set; return *this; } void Scatter::DrawLegend(Draw& w,const int& scale) const { Vector L; L.Append(vLegend); L.Append(vFLegend); Vector Thick; Thick.Append(vPThickness); Thick.Append(vFThickness); Vector LC; LC.Append(vPColors); LC.Append(vFColors); Vector LW; LW.Append(vPWidth); VectorVJ; VJ.Append(vJoin); Vector MS; MS.Append(vMarkStyles); Vector MC; MC.Append(vMarkColors); Vector Patt; Patt.Append(vPPattern); Patt.Append(vFPattern); int NMR=fround((GetSize().cx-2*px)/legendWeight);//max number of labels per row if (NMR>0) { int N=L.GetCount();//number of labels int Nc;//number of complete rows int LCR;//number of labels on complete row int R;//number of remaining labels on incomplete row if(NMR>N) {Nc=0; LCR=0; R=N;} else if (NMR==N) {Nc=1; LCR=N; R=0;} else {Nc=N/NMR; LCR=NMR; R=N%NMR;} for(int j=0;j<=Nc;j++) { int start=N-(j+1)*LCR; int end=N-j*LCR; if (j==Nc) {start=0; end=R;} for(int i=start;i vp; vp << Point(scale*(i-start)*legendWeight, scale*(4-12*(j+1))) << Point(scale*(i-start)*legendWeight+scale*23, scale*(4-12*(j+1))); if (VJ.At(i)) DrawPolylineX(w, vp, scale*Thick.At(i)/6, LC.At(i), Patt.At(i), scale); Point p(scale*((i-start)*legendWeight+7),scale*(4-12*(j+1))/*+scale*Thick.At(i)/12*/); if (LW.At(i,0) > 1) DrawMark(MS.At(i),w,scale,p,LW.At(i,0),MC.At(i)); Font scaledFont; scaledFont.Height(scale*StdFont().GetHeight()); w.DrawText(scale*(i-start)*legendWeight+scale*25, scale*(-2-12*(j+1)), L.At(i), scaledFont,LC.At(i)); } } } } void Scatter::AdjustMinUnitX() { if (xMajorUnit > 0) { while (xMinUnit < 0) xMinUnit += xMajorUnit; while (xMinUnit > xMajorUnit) xMinUnit -= xMajorUnit; } } void Scatter::AdjustMinUnitY() { if (yMajorUnit > 0) { while (yMinUnit < 0) yMinUnit += yMajorUnit; while (yMinUnit > yMajorUnit) yMinUnit -= yMajorUnit; } } void Scatter::AdjustMinUnitY2() { if (yMajorUnit2 > 0) { while (yMinUnit2 < 0) yMinUnit2 += yMajorUnit2; while (yMinUnit2 > yMajorUnit2) yMinUnit2 -= yMajorUnit2; } } Scatter &Scatter::SetRange(double rx, double ry, double ry2) { if (rx <= 0 || ry <= 0 || ry2 <= 0) throw (Exc(t_("Invalid graph range"))); xRange=rx; yRange=ry; yRange2=ry2; xMajorUnit=xRange/10; AdjustMinUnitX(); yMajorUnit=yRange/10; AdjustMinUnitY(); yMajorUnit2=yRange2/10; AdjustMinUnitY2(); WhenSetRange(); return *this; } Scatter &Scatter::SetMajorUnits(double ux, double uy) { //if (ux > xRange) throw (Exc(t_("Invalid X major units!"))); //if (uy > yRange) throw (Exc(t_("Invalid Y major units!"))); xMajorUnit=ux; yMajorUnit=uy; yMajorUnit2=yRange2*yMajorUnit/yRange; AdjustMinUnitX(); AdjustMinUnitY(); AdjustMinUnitY2(); return *this; } Scatter &Scatter::SetMinUnits(double ux, double uy) { xMinUnit=ux; yMinUnit=uy; yMinUnit2=yRange2*yMinUnit/yRange; AdjustMinUnitX(); AdjustMinUnitY(); AdjustMinUnitY2(); return *this; } Scatter &Scatter::SetXYMin(double xmin, double ymin, double ymin2) { xMin=xmin; yMin=ymin; yMin2=ymin2; WhenSetXYMin(); return *this; } void Scatter::FitToData(bool Y) { double minx, maxx, miny, miny2, maxy, maxy2; minx = miny = miny2 = -DOUBLE_NULL; maxx = maxy = maxy2 = DOUBLE_NULL; for (int j=0; j maxx) maxx = vPointsData[j][i].x; } } for (int j=0; j maxy) maxy = vPointsData[j][i].y; } else { if (vPointsData[j][i].y < miny2) miny2 = vPointsData[j][i].y; if (vPointsData[j][i].y > maxy2) maxy2 = vPointsData[j][i].y; } } } for (int j=0; j & points,const String& legend,const bool& join, const class::Color& pcolor, const int& width, const int& thickness) { vPointsData.AddPick(points); vJoin.Add(join); vSmooth.Add(false); vPColors.Add(pcolor); vPWidth.Add(width); vPThickness.Add(thickness); vLegend.Add(legend); vMarkColors.Add(pcolor); if (width <= 1) vShowMark.Add(false); else vShowMark.Add(true); vMarkStyles.Add(CIRCLE); vPPrimaryY.Add(true); vPSequential.Add(sequentialXAll); vPPattern.Add(LINE_SOLID); Refresh(); return *this; } Color GetNewColor(int id) { switch(id) { case 0: return LtBlue(); case 1: return LtRed(); case 2: return LtGreen(); case 3: return Black(); case 4: return LtGray(); case 5: return Yellow(); case 6: return Brown(); case 7: return Blue(); case 8: return Red(); case 9: return Green(); case 10:return Gray(); } return Color(Random(), Random(), Random()); } #define LINE_DOTTED "o..." #define LINE_DOTTED_SEP "o..........." #define LINE_DASHED "oooooo......" #define LINE_DASH_DOT "ooooo...o..." #define LINE_SOLID "oooooooooooo" String GetNewPattern(int id) { switch(id) { case 0: return LINE_SOLID; case 1: return LINE_DOTTED; case 2: return LINE_DASHED; case 3: return LINE_DASH_DOT; case 4: return LINE_SOLID; case 5: return LINE_DOTTED; case 6: return LINE_DASHED; case 7: return LINE_DASH_DOT; } String ret = "oo"; dword r = Random(); return ret << (r & 1 ? "oo" : "..") << (r & 2 ? "oo" : "..") << (r & 4 ? "oo" : ".."); } Scatter &Scatter::Stroke(int width, class::Color pcolor, String pattern) { int id = vPointsData.GetCount() - 1; vJoin[id] = width > 0; if (IsNull(pcolor)) pcolor = GetNewColor(id); vPColors[id] = pcolor; vPThickness[id] = width; if (IsNull(pattern)) pattern = GetNewPattern(id); vPPattern[id] = pattern; Refresh(); return *this; } Scatter &Scatter::Mark(int thickness, class::Color pcolor, MarkStyle style) { int id = vPointsData.GetCount() - 1; vPWidth[id] = thickness; if (IsNull(pcolor)) pcolor = GetNewColor(id); vMarkColors[id] = pcolor; vShowMark[id] = thickness > 0; vMarkStyles[id] = style; Refresh(); return *this; } Scatter &Scatter::SetPattern(const String pattern) { vPPattern[vPPattern.GetCount()-1] = pattern; return *this; } void Scatter::AddPoint(const int& j, const XY & point, const bool& refresh) { if(IsValid(j)) { vPointsData[j].Add(point); if(refresh) Refresh(); } } void Scatter::InsertPoint(const int& j, const int& i, const XY & point) { if(IsValid(j)) { if(i>=0 && vPointsData[j].GetCount()>=i) { vPointsData[j].Insert(i,point); Refresh(); } } } void Scatter::RemovePoint(const int& j, const int& i) { if(IsValid(j)) { if(i>=0 && vPointsData[j].GetCount()>i) { vPointsData[j].Remove(i); Refresh(); } } } void Scatter::SetData(const int& j, const int& i, const XY & point) { if(IsValid(j)) { if(i>=0 && vPointsData[j].GetCount()>i) { vPointsData[j][i]=point; Refresh(); } } } void Scatter::SetData(const int& j, Vector & points) { if(IsValid(j)) { vPointsData[j]<<=points; Refresh(); } } void Scatter::SetDataColor(const int& j, const class::Color& pcolor) { if(IsValid(j)) { vPColors[j]=pcolor; Refresh(); } } void Scatter::SetFunctColor(const int& j, const class::Color& fcolor) { if(IsValid(j)) { vFColors[j]=fcolor; Refresh(); } } Color Scatter::GetDataColor(const int& j) const { if(IsValid(j)) { return vPColors[j]; } throw (Exc(t_("Invalid series index!"))); } Color Scatter::GetFunctColor(const int& j) const { if(IsValid(j)) { return vFColors[j]; } throw (Exc(t_("Invalid function index!"))); } void Scatter::SetDataThickness(const int& j, const int& thick_dots) { if(IsValid(j)) { vPThickness[j]=thick_dots; Refresh(); } } void Scatter::SetFunctThickness(const int& j, const int& thick_dots) { if(IsValid(j)) { vFThickness[j]=thick_dots; Refresh(); } } int Scatter::GetDataThickness(const int& j) const { if(IsValid(j)) { return vPThickness[j]; } throw (Exc(t_("Invalid series index!"))); } int Scatter::GetFunctThickness(const int& j) const { if(IsValid(j)) { return vFThickness[j]; } throw (Exc(t_("Invalid series index!"))); } void Scatter::SetMarkWidth(const int& j, const int& width_dots) { if(IsValid(j)) { vPWidth[j]=width_dots; Refresh(); } } int Scatter::GetMarkWidth(const int& j) const { if(IsValid(j)) { return vPWidth[j]; } throw (Exc(t_("Invalid series index!"))); } void Scatter::SetMarkStyle(const int& j, MarkStyle noStyle) { if(IsValid(j)) { vMarkStyles[j]=noStyle; Refresh(); } } int Scatter::GetMarkStyle(const int& j) const { if(IsValid(j)) { return vMarkStyles[j]; } throw (Exc(t_("Invalid series index!"))); } void Scatter::SetMarkColor(const int& j, const ::Color& mcolor) { if(IsValid(j)) { vMarkColors[j]=mcolor; Refresh(); } } Color Scatter::GetMarkColor(const int& j) const { if(IsValid(j)) { return vMarkColors[j]; } throw (Exc(t_("Invalid series index!"))); } void Scatter::SetShowMark(const int& j, const bool& show) { if(IsValid(j)) { vShowMark[j]=show; Refresh(); } } bool Scatter::IsMarkShow(const int& j) const throw (Exc) { if(!IsValid(j)) throw (Exc(t_("Invalid series index!"))); return vShowMark[j]; } void Scatter::SetJoin(const int& j, const bool& join) { if(IsValid(j)) { vJoin[j]=join; Refresh(); } } bool Scatter::IsJoined(const int& j) const throw (Exc) { if(!IsValid(j)) throw (Exc(t_("Invalid series index!"))); return vJoin[j]; } void Scatter::SetSmooth(const int& j, const bool& smooth) { if(IsValid(j)) { vSmooth[j]=smooth; Refresh(); } } bool Scatter::IsSmooth(const int& j) const throw (Exc) { if(!IsValid(j)) throw (Exc(t_("Invalid series index!"))); return vSmooth[j]; } void Scatter::SetDataPrimaryY(const int& j, const bool& primary) { if(IsValid(j)) { vPPrimaryY[j]=primary; Refresh(); } } Scatter &Scatter::SetDataPrimaryY(const bool& primary) { SetDataPrimaryY(vPPrimaryY.GetCount()-1, primary); return *this; } bool Scatter::IsDataPrimaryY(const int& j) const throw (Exc) { if(!IsValid(j)) throw (Exc(t_("Invalid series index!"))); return vPPrimaryY[j]; } void Scatter::SetSequentialX(const int& j, const bool& sequential) { if(IsValid(j)) { vPSequential[j]=sequential; Refresh(); } } Scatter &Scatter::SetSequentialX(const bool& sequential) { SetSequentialX(vPSequential.GetCount()-1, sequential); return *this; } Scatter &Scatter::SetSequentialXAll(const bool& sequential) { for (int i = 0; i < vPSequential.GetCount(); ++i) SetSequentialX(i, sequential); sequentialXAll = sequential; return *this; } void Scatter::SetFunctPrimaryY(const int& j, const bool& primary) { if(IsValid(j)) { vFPrimaryY[j]=primary; Refresh(); } } Scatter &Scatter::SetFunctPrimaryY(const bool& primary) { SetFunctPrimaryY(vFPrimaryY.GetCount()-1, primary); return *this; } bool Scatter::IsFunctPrimaryY(const int& j) const throw (Exc) { if(!IsValid(j)) throw (Exc(t_("Invalid series index!"))); return vFPrimaryY[j]; } void Scatter::RemoveSeries(const int& j) { if (IsValid(j)) { vPointsData.Remove(j); vJoin.Remove(j); vSmooth.Remove(j); vPColors.Remove(j); vPWidth.Remove(j); vPThickness.Remove(j); vLegend.Remove(j); vMarkColors.Remove(j); vShowMark.Remove(j); vMarkStyles.Remove(j); vPPrimaryY.Remove(j); vPPattern.Remove(j); vPSequential.Remove(j); Refresh(); } } void Scatter::RemoveAllSeries() { vPointsData.Clear(); vJoin.Clear(); vSmooth.Clear(); vPColors.Clear(); vPWidth.Clear(); vPThickness.Clear(); vLegend.Clear(); vMarkColors.Clear(); vShowMark.Clear(); vMarkStyles.Clear(); vPPrimaryY.Clear(); vPSequential.Clear(); vPPattern.Clear(); Refresh(); } void Scatter::PlotFunction(PlotFunc f, const String& legend, const class::Color& fcolor, const int& weight) { Vector series; vFunctionData.AddPick(series); vAdress.Add(f); vFColors.Add(fcolor); vFThickness.Add(weight); vFLegend.Add(legend); vFPrimaryY.Add(true); vFPattern.Add(LINE_SOLID); Refresh(); } void Scatter::PlotParaFunction(PlotParamFunc f, const String& legend, const class::Color& fcolor, const int& weight,const int& Np) { double t;//t must be choosed between [0,1] Vector series; for (int i=0; i<=Np;i++) { t=(double)i/Np; //series<j) { if(vFunctionData[j].IsEmpty()) { int nf=-1; for(int i=0; i<=j; i++) { if (vFunctionData[i].IsEmpty()) nf++; } vAdress.Remove(nf); } vFunctionData.Remove(j); vFColors.Remove(j); vFThickness.Remove(j); vFLegend.Remove(j); vFPrimaryY.Remove(j); vFPattern.Remove(j); Refresh(); } } void Scatter::RemoveAllFSeries() { vAdress.Clear(); vFunctionData.Clear(); vFColors.Clear(); vFThickness.Clear(); vFLegend.Clear(); vFPrimaryY.Clear(); vFPattern.Clear(); Refresh(); } Drawing Scatter::GetDrawing() const { DrawingDraw ddw(6*GetSize()); SetDrawing (ddw, 6); return ddw; } Image Scatter::GetImage(const int& scale) { bool aa=antialiasing; antialiasing=false; ImageDraw idraw(scale*GetSize()); SetDrawing (idraw,scale); antialiasing=aa; return idraw; } #ifdef PLATFORM_WIN32 void Scatter::SaveAsMetafile(const char* file) const { GuiLock __; WinMetaFileDraw wmfd; wmfd.Create(6*GetSize().cx,6*GetSize().cy,"Scatter","chart",file); SetDrawing (wmfd, 6); wmfd.Close(); } void Scatter::SaveToClipboard(bool saveAsMetafile) { GuiLock __; if (saveAsMetafile) { WinMetaFileDraw wmfd; wmfd.Create(6*GetSize().cx,6*GetSize().cy,"Scatter","chart"); SetDrawing (wmfd, 6); WinMetaFile wmf = wmfd.Close(); wmf.WriteClipboard(); } else { Image img = GetImage(3); WriteClipboardImage(img); } } #else void Scatter::SaveToClipboard(bool) { GuiLock __; Image img = GetImage(3); WriteClipboardImage(img); } #endif double Scatter::GetXByPoint(const int x) { return (x-GetH_Border())*GetXRange()/(GetSize().cx-2*GetH_Border()-1)+GetXMin(); } double Scatter::GetYByPoint(const int y) { return (GetSize().cy-GetV_Border()-y-1)*GetYRange()/(GetSize().cy-2*GetV_Border()-GetTitleFont().GetHeight()-1)+GetYMin(); } double Scatter::GetY2ByPoint(const int y) { return (GetSize().cy-GetV_Border()-y-1)*GetY2Range()/(GetSize().cy-2*GetV_Border()-GetTitleFont().GetHeight()-1)+GetYMin2(); } double Scatter::GetXPointByValue(const double x) { return (x-GetXMin())/GetXRange()*(GetSize().cx-2*GetH_Border()-1)+GetH_Border(); } double Scatter::GetYPointByValue(const double y) { return (GetSize().cy-GetV_Border()-1)-(y-GetYMin())/GetYRange()*(GetSize().cy-2*GetV_Border()-GetTitleFont().GetHeight()-1); } void Scatter::Paint(Draw& w) { SetDrawing(w,1); } Scatter &Scatter::ShowInfo(bool show) { paintInfo=show; return *this; } void Scatter::ProcessPopUp(const Point & pt) { double _x= (popLT.x-px)*xRange/(GetSize().cx-2*px-1)+xMin; double _y= (GetSize().cy-py-popLT.y-1)*yRange/(GetSize().cy-2*py-titleFont.GetHeight()-1)+yMin; double _y2=(GetSize().cy-py-popLT.y-1)*yRange2/(GetSize().cy-2*py-titleFont.GetHeight()-1)+yMin2; double x= (pt.x-px)*xRange/(GetSize().cx-2*px-1)+xMin; double y= (GetSize().cy-py-pt.y-1)*yRange/(GetSize().cy-2*py-titleFont.GetHeight()-1)+yMin; double y2=(GetSize().cy-py-pt.y-1)*yRange2/(GetSize().cy-2*py-titleFont.GetHeight()-1)+yMin2; double dx = x - _x; double dy = y - _y; double dy2 = y2 - _y2; if(logX) { x = pow(10.0, x); _x = pow(10.0, _x); dx = pow(10.0, dx); } if(logY) { y = pow(10.0, y); _y = pow(10.0, _y); dy = pow(10.0, dy); } if(logY2) { y2 = pow(10.0, y2); _y2 = pow(10.0, _y2); dy2 = pow(10.0, dy2); } String strx, _strx, dstrx, stry, _stry, dstry; if (cbModifFormatX) { cbModifFormatX(strx, 0, x); strx.Replace("\n", " "); cbModifFormatX(_strx, 0, _x); _strx.Replace("\n", " "); } else { strx = VariableFormatX(x); _strx = VariableFormatX(_x); } if (cbModifFormatDeltaX) { cbModifFormatDeltaX(dstrx, 0, dx); dstrx.Replace("\n", " "); } else { dstrx = VariableFormatX(dx); } if (cbModifFormatY) { cbModifFormatY(stry, 0, y); stry.Replace("\n", " "); cbModifFormatY(_stry, 0, _y); _stry.Replace("\n", " "); } else { stry = VariableFormatY(y); _stry = VariableFormatY(_y); } if (cbModifFormatDeltaY) { cbModifFormatDeltaY(dstry, 0, dy); dstry.Replace("\n", " "); } else { dstry = VariableFormatY(dy); } String str= popTextX + ": " + _strx; if (strx != _strx) str << "; " + popTextX + "': " + strx + "; Δ" + popTextX + ": " + dstrx; str << "\n" + popTextY + ": " + _stry; if (stry != _stry) str << "; " + popTextY + "': " + stry + "; Δ" + popTextY + ": " + dstry; if (drawY2Reticle) { String stry2, _stry2, dstry2; if (cbModifFormatY2) { cbModifFormatY2(stry2, 0, y2); stry2.Replace("\n", " "); cbModifFormatY2(_stry2, 0, _y2); _stry2.Replace("\n", " "); } else { stry2 = VariableFormatY2(y2); _stry2 = VariableFormatY2(_y2); } if (cbModifFormatDeltaY2) { cbModifFormatDeltaY2(dstry2, 0, dy2); dstry2.Replace("\n", " "); } else { dstry2 = VariableFormatY(dy2); } str << "\n" + popTextY2 + ": " + _stry2; if (stry2 != _stry2) str << "; " + popTextY2 + ": " + stry2 + "; Δ" + popTextY2 + ": " + dstry2; } const Point p2 = pt+offset; popText.SetText(str).Move(this,p2.x,p2.y); } void Scatter::DoMouseAction(bool down, Point pt, MouseAction action, int value) { switch (action) { case SCROLL: Scrolling(down, pt); break; case ZOOM_H_ENL: case ZOOM_H_RED: MouseZoom(value, true, false); break; case ZOOM_V_ENL: case ZOOM_V_RED: MouseZoom(value, false, true); break; case SHOW_INFO: LabelPopUp(down, pt); break; case CONTEXT_MENU: if(showContextMenu) MenuBar::Execute(THISBACK(ContextMenu)); break; } } bool Scatter::SetMouseBehavior(MouseBehaviour *_mouseBehavior) { if (!_mouseBehavior) return false; int i; for (i = 0; _mouseBehavior[i].action != NO_ACTION && i < MAX_MOUSEBEHAVIOR; ++i) ; if (i == MAX_MOUSEBEHAVIOR) return false; mouseBehavior = _mouseBehavior; return true; } void Scatter::ProcessMouse(bool down, Point &pt, bool ctrl, bool alt, bool shift, bool left, bool middle, int middleWheel, bool right) { for (int i = 0; mouseBehavior[i].action != NO_ACTION && i < MAX_MOUSEBEHAVIOR; ++i) { if (mouseBehavior[i].ctrl == ctrl && mouseBehavior[i].alt == alt && mouseBehavior[i].shift == shift && mouseBehavior[i].left == left && mouseBehavior[i].middle == middle && mouseBehavior[i].right == right && ((mouseBehavior[i].middleWheel == 0) || mouseBehavior[i].middleWheel == ((middleWheel > 0) - (middleWheel < 0)))) DoMouseAction(down, pt, mouseBehavior[i].action, middleWheel); } } void Scatter::LabelPopUp(bool down, Point &pt) { if (down) { if(paintInfo && px <=pt.x && pt.x<= GetSize().cx-px && (py + titleFont.GetHeight())<=pt.y && pt.y<= GetSize().cy-py) { popText.AppearOnly(this); isLabelPopUp = true; if (IsNull(popLT)) popLT = pt; popRB = pt; ProcessPopUp(pt); } } else { if(paintInfo && isLabelPopUp) { popText.Close(); isLabelPopUp = false; popLT = popRB = Null; Refresh(); } } } #ifdef PLATFORM_LINUX #include #endif void Scatter::Scrolling(bool down, Point &pt, bool isOut) { static Image mouseImg; if (down) { if((mouseHandlingX || mouseHandlingY) && px <=pt.x && pt.x<= GetSize().cx-px && (py + titleFont.GetHeight())<=pt.y && pt.y<= GetSize().cy-py) { butDownX = pt.x; butDownY = pt.y; isScrolling = true; INTERLOCKED { #ifdef PLATFORM_WIN32 static Image img = Win32Cursor(IDC_SIZEALL); #else static Image img = X11Cursor(XC_fleur); #endif mouseImg = Ctrl::OverrideCursor(img); } } } else { if (isScrolling) { if (!isOut) MouseMove(pt, 0); isScrolling = false; Ctrl::OverrideCursor(mouseImg); } } } void Scatter::LeftDown(Point pt, dword keyFlags) { ProcessMouse(true, pt, keyFlags & K_CTRL, keyFlags & K_ALT, keyFlags & K_SHIFT, true, false, 0, false); } void Scatter::LeftUp(Point pt, dword keyFlags) { ProcessMouse(false, pt, keyFlags & K_CTRL, keyFlags & K_ALT, keyFlags & K_SHIFT, true, false, 0, false); } void Scatter::MiddleDown(Point pt, dword keyFlags) { ProcessMouse(true, pt, keyFlags & K_CTRL, keyFlags & K_ALT, keyFlags & K_SHIFT, false, true, 0, false); } void Scatter::MiddleUp(Point pt, dword keyFlags) { ProcessMouse(false, pt, keyFlags & K_CTRL, keyFlags & K_ALT, keyFlags & K_SHIFT, false, true, 0, false); } void Scatter::RightDown(Point pt, dword keyFlags) { ProcessMouse(true, pt, keyFlags & K_CTRL, keyFlags & K_ALT, keyFlags & K_SHIFT, false, false, 0, true); } void Scatter::RightUp(Point pt, dword keyFlags) { ProcessMouse(false, pt, keyFlags & K_CTRL, keyFlags & K_ALT, keyFlags & K_SHIFT, false, false, 0, true); } void Scatter::MouseWheel(Point pt, int zdelta, dword keyFlags) { if (zdelta == 0) return; ProcessMouse(true, pt, keyFlags & K_CTRL, keyFlags & K_ALT, keyFlags & K_SHIFT, false, false, zdelta, false); } void Scatter::MouseMove(Point pt, dword) { if (isScrolling) { int shiftX = pt.x - butDownX; if (mouseHandlingX && shiftX != 0) { double deltaX = shiftX*xRange/(GetSize().cx - 2*px - 1); xMin -= deltaX; xMinUnit += deltaX; AdjustMinUnitX(); butDownX = pt.x; } int shiftY = pt.y - butDownY; if (mouseHandlingY && shiftY != 0) { double deltaY = -shiftY*yRange/(GetSize().cy - 2*py - 1); yMin -= deltaY; yMinUnit += deltaY; AdjustMinUnitY(); if (drawY2Reticle) { double deltaY2 = -shiftY*yRange2/(GetSize().cy - 2*py - 1); yMin2 -= deltaY2; yMinUnit2 += deltaY2; AdjustMinUnitY2(); } butDownY = pt.y; } if ((mouseHandlingX && shiftX != 0) || (mouseHandlingY && shiftY != 0)) { WhenSetXYMin(); Refresh(); WhenZoomScroll(); } } if(isLabelPopUp) { if (paintInfo && px <=pt.x && pt.x<= GetSize().cx-px && (py + titleFont.GetHeight())<=pt.y && pt.y<= GetSize().cy-py) { if (IsNull(popLT)) popLT = pt; popRB = pt; popText.AppearOnlyOpen(this); ProcessPopUp(pt); Refresh(); } } } void Scatter::MouseLeave() { Point p = Null; Scrolling(false, p, true); } void Scatter::MouseZoom(int zdelta, bool hor, bool ver) { double scale = zdelta > 0 ? zdelta/100. : -100./zdelta; Zoom(scale, mouseHandlingX, mouseHandlingY); } void Scatter::Zoom(double scale, bool mouseX, bool mouseY) { mouseX = mouseX && ((minXZoom > 0 && xRange*scale > minXZoom) || (minXZoom < 0)); mouseX = mouseX && ((maxXZoom > 0 && xRange*scale < maxXZoom) || (maxXZoom < 0)); mouseY = mouseY && ((minYZoom > 0 && yRange*scale > minYZoom) || (minYZoom < 0)); mouseY = mouseY && ((maxYZoom > 0 && yRange*scale < maxYZoom) || (maxYZoom < 0)); //mouseX = mouseX && (!mouseHandlingY || mouseY); //mouseY = mouseY && (!mouseHandlingX || mouseX); if (mouseX) { double oldXMin = xMin; xMin += xRange*(1-scale)/2.; xMinUnit = oldXMin + xMinUnit - xMin; AdjustMinUnitX(); xRange *= scale; } if (mouseY) { yRange *= scale; yRange2 *= scale; } if (mouseX || mouseY) { WhenSetRange(); Refresh(); WhenZoomScroll(); } } void Scatter::Scroll(double factorX, double factorY) { if (factorX != 0) { double deltaX = factorX*xRange; xMin -= deltaX; xMinUnit += deltaX; AdjustMinUnitX(); } if (factorY != 0) { double deltaY = -factorY*yRange; yMin -= deltaY; yMinUnit += deltaY; AdjustMinUnitY(); if (drawY2Reticle) { double deltaY2 = -factorY*yRange2; yMin2 -= deltaY2; yMinUnit2 += deltaY2; AdjustMinUnitY2(); } } if (factorX != 0 || factorY != 0) { Refresh(); WhenZoomScroll(); } } Image Scatter::CursorImage(Point p, dword keyflags) { return ChartImg::cursor1(); } void Scatter::Circle(Draw& w, const int& scale, const Point& cp, const int& size, const class::Color& markColor)const { int radius = fround(scale*size/6); int radius2 = radius/2; w.DrawEllipse(cp.x-radius2, cp.y-radius2, radius, radius, markColor, 1, markColor); } void Scatter::Square(Draw& w, const int& scale, const Point& cp, const int& size, const class::Color& markColor)const { Vector p; p< p; p< p; p< GetLinePattern(String pattern) { Vector ret; ret.Add(); int retPos = 0; ret[0] = 2; for (int i = 1; i < pattern.GetCount(); ++i) { if (pattern[i] != pattern[i-1]) { ret.Add(); retPos++; ret[retPos] = 0; } ret[retPos] += 2; } return ret; } Vector &GetPatternArray(String pattern) { static VectorMap > pats; int pos = pats.Find(pattern); if (pos < 0) { pats.Add(pattern, GetLinePattern(pattern)); pos = pats.GetCount()-1; } return pats.GetValues()[pos]; } void Scatter::DrawLineX(Draw& w, const int x0, const int y0, const int x1, const int y1, int thick, const class::Color &color, String pattern, const int &scale) { Vector p; p.SetCount(2); p[0].x = x0; p[0].y = y0; p[1].x = x1; p[1].y = y1; DrawPolylineX(w, p, thick, color, pattern, scale); } void Scatter::DrawPolylineX(Draw& w, const Vector &p, int thick, const class::Color &color, String pattern, const int &scale) { if (pattern == LINE_SOLID) w.DrawPolyline(p, thick, color); else { Vector &pat = GetPatternArray(pattern); int iPat = 0; double len = pat[0]*scale; // Pixels por barra Pointf begin, end; begin = p[0]; for (int i = 1; i < p.GetCount();) { double d = Dist(begin, p[i]); if (d >= len) end = PointAtLen(begin, p[i], len); else { end = p[i]; len -= d; ++i; } if (Even(iPat)) w.DrawLine(begin, end, thick, color); if (d >= len) { iPat++; if (iPat == pat.GetCount()) iPat = 0; len = pat[iPat]*scale; } begin = end; } } } void Scatter::Plot(Draw& w, const int& scale,const int& l,const int& h)const { double d1=xRange/xMajorUnit; double d2=yRange/yMajorUnit; w.DrawRect(1,1,l-2,h-1,plotAreaColor); //grosimea liniei nu este scalata int gW=fround(gridWidth*scale/6); if(gridWidth<0) gW=gridWidth; Vector p; p.SetCount(2); if (drawVGrid) for(int i=0; xMinUnit+i*xMajorUnit < xRange;i++) { p[0].x = fround(l*xMinUnit/xRange+i*l/d1); p[0].y = 0; p[1].x = fround(l*xMinUnit/xRange+i*l/d1); p[1].y = h; DrawPolylineX(w, p, gW, gridColor, "oo..", scale); } if (drawHGrid) for(int i=0; yMinUnit+i*yMajorUnit < yRange;i++) { p[0].x = 0; p[0].y = fround(-h*yMinUnit/yRange + h-i*h/d2); p[1].x = l; p[1].y = fround(-h*yMinUnit/yRange + h-i*h/d2); DrawPolylineX(w, p, gW, gridColor, "oo..", scale); } w.DrawLine(0, h, l, h, scale, Black); w.DrawLine(0, 0, l, 0, scale, Black); w.DrawLine(0, 0, 0, h, scale, Black); w.DrawLine(l, 0, l, h+1, scale, Black); w.Clip(Rect(0,0,l,h)); int ix;//int x points coordinates int iy;//int y points coordinates if (!vPointsData.IsEmpty()){ for (int j=0; j p1; int imin, imax; if (vPSequential[j]) { imin = imax = Null; for (int i = 1; i= xMin) imin = i-1; } else if (IsNull(imax)) { if (vPointsData[j][i].x >= xMin+xRange) imax = i+1; } } if (IsNull(imin)) imin = 0; if (IsNull(imax)) imax = vPointsData[j].GetCount(); } else { imin = 0; imax = vPointsData[j].GetCount(); } int numV; if (fastViewX) numV = 1+(imax-imin)/l; else numV = 1; for (int i=imin; i 1) { yy = 0; int ii; for (ii = 0; ii < numV && i+ii < imax; ++ii) yy += vPointsData[j][i+ii].y; yy /= double(ii); xx = (vPointsData[j][i].x + vPointsData[j][i+ii-1].x)/2; } else { xx = vPointsData[j][i].x; yy = vPointsData[j][i].y; } ix=fround(l*(xx-xMin)/xRange); if (vPPrimaryY[j]) iy=fround(h*(yy-yMin)/yRange); else iy=fround(h*(yy-yMin2)/yRange2); p1<2) { Vector p2; Vector v(Cubic(vPointsData[j])); for (int i=0; i= 1) { for (int i=0; i<(imax-imin)/numV; i++) DrawMark(vMarkStyles[j],w,scale,p1[i],vPWidth[j],vMarkColors[j]); } } } int nf=0; //number of functions to draw for (int j=0; j p1; for (int i=0; i p1; for(int i=0; i Scatter::Cubic(const Vector& DataSet, const int& fineness,double tension) const { Vector OutSet; if(DataSet.GetCount()>2) { OutSet<(OutSet); } void ParseTextMultiline(const String &text, Font fnt, Array &texts, Array &sizes) { Size ret(0, 0); int npos = 0; for (int pos = 0; npos != -1; pos = npos+1) { npos = text.Find('\n', pos); String &t = texts.Add(); if (npos != -1) t = text.Mid(pos, npos-pos); else t = text.Mid(pos); Size &s = sizes.Add(); s.cx = GetTextSize(t, fnt).cx; s.cy = GetTextSize(t, fnt).cy; } } Size GetTextSizeMultiline(Array &sizes) { Size ret(0, 0); for (int i = 0; i < sizes.GetCount(); ++i) { if (sizes[i].cx > ret.cx) ret.cx = sizes[i].cx; ret.cy += sizes[i].cy; } return ret; } void Scatter::SetDrawing(Draw& w, const int& scale) const { GuiLock __; w.DrawRect(scale*GetSize(),graphColor); Size sz; sz.cx=0; sz.cy=0; if(!title.IsEmpty()) { Font FontTitle6; FontTitle6=titleFont; FontTitle6.Height(scale*titleFont.GetHeight()); FontTitle6.Width(scale*titleFont.GetWidth()); sz= GetTextSize(title, FontTitle6); w.DrawText((scale*GetSize().cx-sz.cx)/2,scale*2,title,FontTitle6,titleColor); } w.Offset(Point(scale*px,scale*py+scale*titleFont.GetHeight())); if(showLegend) DrawLegend(w,scale); int l=scale*GetSize().cx-2*scale*px; int h=scale*GetSize().cy-2*scale*py-scale*titleFont.GetHeight(); Font FontLabel6; FontLabel6=labelsFont; FontLabel6.Height(scale*labelsFont.GetHeight()); Size lx=GetTextSize(xLabel,FontLabel6); Size ly=GetTextSize(yLabel,FontLabel6); Size ly2=GetTextSize(yLabel2,FontLabel6); w.DrawText(fround((l-lx.cx)/2),h+scale*py-lx.cy-scale*2,xLabel,FontLabel6,labelsColor); w.DrawText(scale*2-scale*px,fround((h+ly.cx)/2),900,yLabel,FontLabel6,labelsColor); w.DrawText(fround(l+scale*px-ly2.cy-2*scale),fround((h+ly2.cx)/2),900,yLabel2,FontLabel6,labelsColor); if (drawXReticle) for(int i=0; xMinUnit+i*xMajorUnit<=xRange;i++){ w.DrawLine(fround(l*xMinUnit/xRange+i*l/(xRange/xMajorUnit)), h, fround(l*xMinUnit/xRange+i*l/(xRange/xMajorUnit)), h+scale*4, fround(scale/2), axisColor); Font Standard6; Standard6.Height(scale*StdFont().GetHeight()); double gridX=xMinUnit+i*xMajorUnit+xMin; String gridLabelX; if (cbModifFormatX) cbModifFormatX(gridLabelX, i, gridX); else gridLabelX = VariableFormatX(gridX); Array texts; Array sizes; ParseTextMultiline(gridLabelX, StdFont(), texts, sizes); for (int ii = 0; ii < texts.GetCount(); ++ii) { int cy = ii == 0 ? 0 : sizes[ii-1].cy; w.DrawText(fround(l*xMinUnit/xRange+i*l/(xRange/xMajorUnit) - scale*sizes[ii].cx/2), h+scale*(4+ii*cy), texts[ii], Standard6, axisColor); } } if (drawYReticle) for(int i=0; yMinUnit+i*yMajorUnit<=yRange;i++){ w.DrawLine(-(scale*4), fround(-h*yMinUnit/yRange+h-i*h/(yRange/yMajorUnit)), 0, fround(-h*yMinUnit/yRange+h-i*h/(yRange/yMajorUnit)), fround(scale/2), axisColor); double gridY=yMinUnit+i*yMajorUnit+yMin; String gridLabelY; if (cbModifFormatY) cbModifFormatY(gridLabelY, i, gridY); else gridLabelY = VariableFormatY(gridY); int dx=scale*GetTextSize(gridLabelY,StdFont()).cx; Font Standard6; Standard6.Height(scale*StdFont().GetHeight()); w.DrawText(-dx-scale*6, fround(-h*yMinUnit/yRange+h-i*h/(yRange/yMajorUnit))-scale*8, gridLabelY, Standard6, axisColor); } if (drawY2Reticle) for(int i=0; yMinUnit+i*yMajorUnit<=yRange;i++){ w.DrawLine(l+(scale*4), fround(-h*yMinUnit2/yRange2+h-i*h/(yRange/yMajorUnit)), l, fround(-h*yMinUnit2/yRange2+h-i*h/(yRange/yMajorUnit)), fround(scale/2), axisColor); double gridY2=yMinUnit2+i*yMajorUnit2+yMin2; String gridLabelY2; if (cbModifFormatY2) cbModifFormatY2(gridLabelY2, i, gridY2); else gridLabelY2 = VariableFormatY2(gridY2); Font Standard6; Standard6.Height(scale*StdFont().GetHeight()); w.DrawText(l+scale*10,fround(-h*yMinUnit2/yRange2+h-i*h/(yRange/yMajorUnit))-scale*8,gridLabelY2,Standard6,axisColor); } if(antialiasing && w.IsGui()) // IsGui() is always false in Linux { ImageDraw imdraw(3*l,3*h); Plot (imdraw,3,3*l,3*h); w.DrawImage(0,0,l,h,imdraw); } else Plot(w,scale,l,h); w.End(); } Scatter::Scatter(): title (""), titleColor(SColorText), graphColor(White), titleFont(Roman(20)), xLabel(""),yLabel(""), labelsFont(StdFont()), labelsColor(SColorText), plotAreaColor(SColorLtFace), axisColor(SColorText), axisWidth(6), px(30), py(30), xRange(100.0), yRange(100.0), yRange2(100.0), xMajorUnit(xRange/10), yMajorUnit(yRange/5), xMin(0.0), yMin(0.0), yMin2(0.0), xMinUnit(0.0), yMinUnit(0.0), yMinUnit2(0.0), logX(false), logY(false), logY2(false), cbModifFormatX(NULL),cbModifFormatY(NULL),cbModifFormatY2(NULL), cbModifFormatDeltaX(NULL),cbModifFormatDeltaY(NULL),cbModifFormatDeltaY2(NULL), gridColor(SColorDkShadow), gridWidth(4), paintInfo(false), mouseHandlingX(false), mouseHandlingY(false), isScrolling(false), isLabelPopUp(false), drawXReticle(true), drawYReticle(true), drawY2Reticle(false), drawVGrid(true), drawHGrid(true), showLegend(true),legendWeight(80), antialiasing(false), offset(10,12), minXZoom(-1), maxXZoom(-1), minYZoom(-1), maxYZoom(-1), fastViewX(false), sequentialXAll(false), popTextX("x"), popTextY("y1"), popTextY2("y2"), popLT(Null), popRB(Null), showContextMenu(false) { Color(graphColor); BackPaint(); popText.SetColor(SColorFace); SetMouseBehavior(defaultMouse); }