30 using size_type = std::vector<TPoint>::size_type;
33 void ConvertPoints(TVirtualPad *pad,
unsigned nPoints,
const T *xs,
const T *ys,
34 std::vector<TPoint> &dst);
36 void MergePointsX(std::vector<TPoint> &points,
unsigned nMerged, SCoord_t yMin,
37 SCoord_t yMax, SCoord_t yLast);
40 size_type MergePointsInplaceY(std::vector<TPoint> &dst, size_type nMerged, SCoord_t xMin,
41 SCoord_t xMax, SCoord_t xLast, size_type first);
44 void ConvertPointsAndMergePassX(TVirtualPad *pad,
unsigned nPoints,
const T *x,
const T *y,
45 std::vector<TPoint> &dst);
47 void ConvertPointsAndMergeInplacePassY(std::vector<TPoint> &dst);
50 void DrawFillAreaAux(TVirtualPad *pad, Int_t nPoints,
const T *xs,
const T *ys);
53 void DrawPolyLineAux(TVirtualPad *pad,
unsigned nPoints,
const T *xs,
const T *ys);
56 void DrawPolyMarkerAux(TVirtualPad *pad,
unsigned nPoints,
const T *xs,
const T *ys);
61 ClassImp(TPadPainter);
72 TPadPainter::TPadPainter()
89 Color_t TPadPainter::GetLineColor()
const
91 return gVirtualX->GetLineColor();
98 Style_t TPadPainter::GetLineStyle()
const
100 return gVirtualX->GetLineStyle();
107 Width_t TPadPainter::GetLineWidth()
const
109 return gVirtualX->GetLineWidth();
116 void TPadPainter::SetLineColor(Color_t lcolor)
118 gVirtualX->SetLineColor(lcolor);
125 void TPadPainter::SetLineStyle(Style_t lstyle)
127 gVirtualX->SetLineStyle(lstyle);
134 void TPadPainter::SetLineWidth(Width_t lwidth)
136 gVirtualX->SetLineWidth(lwidth);
143 Color_t TPadPainter::GetFillColor()
const
145 return gVirtualX->GetFillColor();
152 Style_t TPadPainter::GetFillStyle()
const
154 return gVirtualX->GetFillStyle();
161 Bool_t TPadPainter::IsTransparent()
const
164 return gVirtualX->IsTransparent();
171 void TPadPainter::SetFillColor(Color_t fcolor)
173 gVirtualX->SetFillColor(fcolor);
180 void TPadPainter::SetFillStyle(Style_t fstyle)
182 gVirtualX->SetFillStyle(fstyle);
189 void TPadPainter::SetOpacity(Int_t percent)
191 gVirtualX->SetOpacity(percent);
198 Short_t TPadPainter::GetTextAlign()
const
200 return gVirtualX->GetTextAlign();
207 Float_t TPadPainter::GetTextAngle()
const
209 return gVirtualX->GetTextAngle();
216 Color_t TPadPainter::GetTextColor()
const
218 return gVirtualX->GetTextColor();
225 Font_t TPadPainter::GetTextFont()
const
227 return gVirtualX->GetTextFont();
234 Float_t TPadPainter::GetTextSize()
const
236 return gVirtualX->GetTextSize();
243 Float_t TPadPainter::GetTextMagnitude()
const
245 return gVirtualX->GetTextMagnitude();
252 void TPadPainter::SetTextAlign(Short_t align)
254 gVirtualX->SetTextAlign(align);
261 void TPadPainter::SetTextAngle(Float_t tangle)
263 gVirtualX->SetTextAngle(tangle);
270 void TPadPainter::SetTextColor(Color_t tcolor)
272 gVirtualX->SetTextColor(tcolor);
279 void TPadPainter::SetTextFont(Font_t tfont)
281 gVirtualX->SetTextFont(tfont);
288 void TPadPainter::SetTextSize(Float_t tsize)
290 gVirtualX->SetTextSize(tsize);
297 void TPadPainter::SetTextSizePixels(Int_t npixels)
299 gVirtualX->SetTextSizePixels(npixels);
306 Int_t TPadPainter::CreateDrawable(UInt_t w, UInt_t h)
308 return gVirtualX->OpenPixmap(Int_t(w), Int_t(h));
315 void TPadPainter::ClearDrawable()
317 gVirtualX->ClearWindow();
324 void TPadPainter::CopyDrawable(Int_t device, Int_t px, Int_t py)
326 gVirtualX->CopyPixmap(device, px, py);
333 void TPadPainter::DestroyDrawable(Int_t device)
335 gVirtualX->SelectWindow(device);
336 gVirtualX->ClosePixmap();
343 void TPadPainter::SelectDrawable(Int_t device)
345 gVirtualX->SelectWindow(device);
351 void TPadPainter::DrawPixels(
const unsigned char * , UInt_t , UInt_t ,
352 Int_t , Int_t , Bool_t )
360 void TPadPainter::DrawLine(Double_t x1, Double_t y1, Double_t x2, Double_t y2)
362 if (GetLineWidth()<=0)
return;
364 const Int_t px1 = gPad->XtoPixel(x1);
365 const Int_t px2 = gPad->XtoPixel(x2);
366 const Int_t py1 = gPad->YtoPixel(y1);
367 const Int_t py2 = gPad->YtoPixel(y2);
368 gVirtualX->DrawLine(px1, py1, px2, py2);
375 void TPadPainter::DrawLineNDC(Double_t u1, Double_t v1, Double_t u2, Double_t v2)
377 if (GetLineWidth()<=0)
return;
379 const Int_t px1 = gPad->UtoPixel(u1);
380 const Int_t py1 = gPad->VtoPixel(v1);
381 const Int_t px2 = gPad->UtoPixel(u2);
382 const Int_t py2 = gPad->VtoPixel(v2);
383 gVirtualX->DrawLine(px1, py1, px2, py2);
390 void TPadPainter::DrawBox(Double_t x1, Double_t y1, Double_t x2, Double_t y2, EBoxMode mode)
392 if (GetLineWidth()<=0 && mode == TVirtualPadPainter::kHollow)
return;
394 Int_t px1 = gPad->XtoPixel(x1);
395 Int_t px2 = gPad->XtoPixel(x2);
396 Int_t py1 = gPad->YtoPixel(y1);
397 Int_t py2 = gPad->YtoPixel(y2);
400 if (TMath::Abs(px2 - px1) < 1)
402 if (TMath::Abs(py1 - py2) < 1)
405 gVirtualX->DrawBox(px1, py1, px2, py2, (TVirtualX::EBoxMode)mode);
411 void TPadPainter::DrawFillArea(Int_t nPoints,
const Double_t *xs,
const Double_t *ys)
414 ::Error(
"TPadPainter::DrawFillArea",
"invalid number of points %d", nPoints);
418 DrawFillAreaAux(gPad, nPoints, xs, ys);
425 void TPadPainter::DrawFillArea(Int_t nPoints,
const Float_t *xs,
const Float_t *ys)
428 ::Error(
"TPadPainter::DrawFillArea",
"invalid number of points %d", nPoints);
432 DrawFillAreaAux(gPad, nPoints, xs, ys);
438 void TPadPainter::DrawPolyLine(Int_t n,
const Double_t *xs,
const Double_t *ys)
440 if (GetLineWidth()<=0)
return;
443 ::Error(
"TPadPainter::DrawPolyLine",
"invalid number of points");
447 DrawPolyLineAux(gPad, n, xs, ys);
454 void TPadPainter::DrawPolyLine(Int_t n,
const Float_t *xs,
const Float_t *ys)
456 if (GetLineWidth()<=0)
return;
459 ::Error(
"TPadPainter::DrawPolyLine",
"invalid number of points");
463 DrawPolyLineAux(gPad, n, xs, ys);
470 void TPadPainter::DrawPolyLineNDC(Int_t n,
const Double_t *u,
const Double_t *v)
472 if (GetLineWidth()<=0)
return;
475 ::Error(
"TPadPainter::DrawPolyLineNDC",
"invalid number of points %d", n);
479 std::vector<TPoint> xy(n);
481 for (Int_t i = 0; i < n; ++i) {
482 xy[i].fX = (SCoord_t)gPad->UtoPixel(u[i]);
483 xy[i].fY = (SCoord_t)gPad->VtoPixel(v[i]);
486 gVirtualX->DrawPolyLine(n, &xy[0]);
493 void TPadPainter::DrawPolyMarker(Int_t n,
const Double_t *x,
const Double_t *y)
496 ::Error(
"TPadPainter::DrawPolyMarker",
"invalid number of points %d", n);
500 DrawPolyMarkerAux(gPad, n, x, y);
507 void TPadPainter::DrawPolyMarker(Int_t n,
const Float_t *x,
const Float_t *y)
510 ::Error(
"TPadPainter::DrawPolyMarker",
"invalid number of points %d", n);
514 DrawPolyMarkerAux(gPad, n, x, y);
521 void TPadPainter::DrawText(Double_t x, Double_t y,
const char *text, ETextMode mode)
523 const Int_t px = gPad->XtoPixel(x);
524 const Int_t py = gPad->YtoPixel(y);
525 const Double_t angle = GetTextAngle();
526 const Double_t mgn = GetTextMagnitude();
527 gVirtualX->DrawText(px, py, angle, mgn, text, (TVirtualX::ETextMode)mode);
534 void TPadPainter::DrawText(Double_t x, Double_t y,
const wchar_t *text, ETextMode mode)
536 const Int_t px = gPad->XtoPixel(x);
537 const Int_t py = gPad->YtoPixel(y);
538 const Double_t angle = GetTextAngle();
539 const Double_t mgn = GetTextMagnitude();
540 gVirtualX->DrawText(px, py, angle, mgn, text, (TVirtualX::ETextMode)mode);
547 void TPadPainter::DrawTextNDC(Double_t u, Double_t v,
const char *text, ETextMode mode)
549 const Int_t px = gPad->UtoPixel(u);
550 const Int_t py = gPad->VtoPixel(v);
551 const Double_t angle = GetTextAngle();
552 const Double_t mgn = GetTextMagnitude();
553 gVirtualX->DrawText(px, py, angle, mgn, text, (TVirtualX::ETextMode)mode);
560 void TPadPainter::SaveImage(TVirtualPad *pad,
const char *fileName, Int_t type)
const
562 if (gVirtualX->InheritsFrom(
"TGCocoa") && !gROOT->IsBatch() &&
563 pad->GetCanvas() && pad->GetCanvas()->GetCanvasID() != -1) {
565 TCanvas *
const canvas = pad->GetCanvas();
569 const UInt_t w = canvas->GetWw();
570 const UInt_t h = canvas->GetWh();
572 const std::unique_ptr<unsigned char[]>
573 pixelData(gVirtualX->GetColorBits(canvas->GetCanvasID(), 0, 0, w, h));
575 if (pixelData.get()) {
576 const std::unique_ptr<TImage> image(TImage::Create());
578 image->DrawRectangle(0, 0, w, h);
579 if (
unsigned char *argb = (
unsigned char *)image->GetArgbArray()) {
581 if (
sizeof(UInt_t) == 4) {
584 std::copy(pixelData.get(), pixelData.get() + 4 * w * h, argb);
588 const unsigned shift = std::numeric_limits<unsigned char>::digits;
590 unsigned *dstPixel = (
unsigned *)argb, *end = dstPixel + w * h;
591 const unsigned char *srcPixel = pixelData.get();
592 for (;dstPixel != end; ++dstPixel, srcPixel += 4) {
594 *dstPixel = srcPixel[0] & (srcPixel[1] << shift) &
595 (srcPixel[2] << 2 * shift) &
596 (srcPixel[3] << 3 * shift);
600 image->WriteImage(fileName, (TImage::EImageFileTypes)type);
608 if (type == TImage::kGif) {
609 gVirtualX->WriteGIF((
char*)fileName);
611 const std::unique_ptr<TImage> img(TImage::Create());
614 img->WriteImage(fileName, (TImage::EImageFileTypes)type);
623 void TPadPainter::DrawTextNDC(Double_t u, Double_t v,
const wchar_t *text, ETextMode mode)
625 const Int_t px = gPad->UtoPixel(u);
626 const Int_t py = gPad->VtoPixel(v);
627 const Double_t angle = GetTextAngle();
628 const Double_t mgn = GetTextMagnitude();
629 gVirtualX->DrawText(px, py, angle, mgn, text, (TVirtualX::ETextMode)mode);
641 void ConvertPoints(TVirtualPad *pad,
unsigned nPoints,
const T *x,
const T *y,
642 std::vector<TPoint> &dst)
649 for (
unsigned i = 0; i < nPoints; ++i) {
650 dst[i].fX = (SCoord_t)pad->XtoPixel(x[i]);
651 dst[i].fY = (SCoord_t)pad->YtoPixel(y[i]);
657 inline void MergePointsX(std::vector<TPoint> &points,
unsigned nMerged, SCoord_t yMin,
658 SCoord_t yMax, SCoord_t yLast)
660 const auto firstPointX = points.back().fX;
661 const auto firstPointY = points.back().fY;
664 points.push_back(TPoint(firstPointX, yLast));
665 }
else if (nMerged == 3) {
666 yMin == firstPointY ? points.push_back(TPoint(firstPointX, yMax)) :
667 points.push_back(TPoint(firstPointX, yMin));
668 points.push_back(TPoint(firstPointX, yLast));
670 points.push_back(TPoint(firstPointX, yMin));
671 points.push_back(TPoint(firstPointX, yMax));
672 points.push_back(TPoint(firstPointX, yLast));
679 inline size_type MergePointsInplaceY(std::vector<TPoint> &dst, size_type nMerged, SCoord_t xMin,
680 SCoord_t xMax, SCoord_t xLast, size_type first)
682 const TPoint &firstPoint = dst[first];
685 dst[first + 1].fX = xLast;
686 dst[first + 1].fY = firstPoint.fY;
687 }
else if (nMerged == 3) {
688 dst[first + 1].fX = xMin == firstPoint.fX ? xMax : xMin;
689 dst[first + 1].fY = firstPoint.fY;
690 dst[first + 2].fX = xLast;
691 dst[first + 2].fY = firstPoint.fY;
693 dst[first + 1].fX = xMin;
694 dst[first + 1].fY = firstPoint.fY;
695 dst[first + 2].fX = xMax;
696 dst[first + 2].fY = firstPoint.fY;
697 dst[first + 3].fX = xLast;
698 dst[first + 3].fY = firstPoint.fY;
711 void ConvertPointsAndMergePassX(TVirtualPad *pad,
unsigned nPoints,
const T *x,
const T *y,
712 std::vector<TPoint> &dst)
716 SCoord_t yMin = 0, yMax = 0, yLast = 0;
717 unsigned nMerged = 0;
720 for (
unsigned i = 0; i < nPoints;) {
721 currentPoint.fX = (SCoord_t)pad->XtoPixel(x[i]);
722 currentPoint.fY = (SCoord_t)pad->YtoPixel(y[i]);
724 yMin = currentPoint.fY;
727 dst.push_back(currentPoint);
731 for (
unsigned j = i + 1; j < nPoints; ++j) {
732 const SCoord_t newX = pad->XtoPixel(x[j]);
734 if (newX == currentPoint.fX) {
735 yLast = pad->YtoPixel(y[j]);
736 yMin = TMath::Min(yMin, yLast);
737 yMax = TMath::Max(yMax, yLast);
741 MergePointsX(dst, nMerged, yMin, yMax, yLast);
747 if (!merged && nMerged > 1)
748 MergePointsX(dst, nMerged, yMin, yMax, yLast);
757 void ConvertPointsAndMergeInplacePassY(std::vector<TPoint> &dst)
760 for (size_type j = 1, nPoints = dst.size(); i < nPoints;) {
762 const TPoint ¤tPoint = dst[i];
764 SCoord_t xMin = currentPoint.fX;
765 SCoord_t xMax = xMin;
769 size_type nMerged = 1;
771 for (; j < nPoints; ++j) {
772 const TPoint &nextPoint = dst[j];
774 if (nextPoint.fY == currentPoint.fY) {
775 xLast = nextPoint.fX;
776 xMin = TMath::Min(xMin, xLast);
777 xMax = TMath::Max(xMax, xLast);
781 nMerged = MergePointsInplaceY(dst, nMerged, xMin, xMax, xLast, i);
787 if (!merged && nMerged > 1)
788 nMerged = MergePointsInplaceY(dst, nMerged, xMin, xMax, xLast, i);
808 void ConvertPointsAndMerge(TVirtualPad *pad,
unsigned threshold,
unsigned nPoints,
const T *x,
809 const T *y, std::vector<TPoint> &dst)
819 dst.reserve(threshold);
821 ConvertPointsAndMergePassX(pad, nPoints, x, y, dst);
823 if (dst.size() < threshold)
826 ConvertPointsAndMergeInplacePassY(dst);
832 void DrawFillAreaAux(TVirtualPad *pad, Int_t nPoints,
const T *xs,
const T *ys)
834 std::vector<TPoint> xy;
836 const Int_t threshold = Int_t(TMath::Min(pad->GetWw() * pad->GetAbsWNDC(),
837 pad->GetWh() * pad->GetAbsHNDC())) * 2;
839 if (threshold <= 0) {
841 ::Error(
"DrawFillAreaAux",
"invalid pad's geometry");
845 if (nPoints < threshold)
846 ConvertPoints(gPad, nPoints, xs, ys, xy);
848 ConvertPointsAndMerge(gPad, threshold, nPoints, xs, ys, xy);
851 if (!gVirtualX->GetFillStyle())
852 xy.push_back(xy.front());
855 gVirtualX->DrawFillArea(xy.size(), &xy[0]);
861 void DrawPolyLineAux(TVirtualPad *pad,
unsigned nPoints,
const T *xs,
const T *ys)
863 std::vector<TPoint> xy;
865 const Int_t threshold = Int_t(TMath::Min(pad->GetWw() * pad->GetAbsWNDC(),
866 pad->GetWh() * pad->GetAbsHNDC())) * 2;
868 if (threshold <= 0) {
869 ::Error(
"DrawPolyLineAux",
"invalid pad's geometry");
873 if (nPoints < (
unsigned)threshold)
874 ConvertPoints(pad, nPoints, xs, ys, xy);
876 ConvertPointsAndMerge(pad, threshold, nPoints, xs, ys, xy);
879 gVirtualX->DrawPolyLine(xy.size(), &xy[0]);
886 void DrawPolyMarkerAux(TVirtualPad *pad,
unsigned nPoints,
const T *xs,
const T *ys)
888 std::vector<TPoint> xy(nPoints);
890 for (
unsigned i = 0; i < nPoints; ++i) {
891 xy[i].fX = (SCoord_t)pad->XtoPixel(xs[i]);
892 xy[i].fY = (SCoord_t)pad->YtoPixel(ys[i]);
895 gVirtualX->DrawPolyMarker(nPoints, &xy[0]);