Logo ROOT  
Reference Guide
Loading...
Searching...
No Matches
TPadPainter.cxx
Go to the documentation of this file.
1// @(#)root/gl:$Id$
2// Author: Olivier Couet, Timur Pocheptsov (vertex merge) 06/05/2009
3
4/*************************************************************************
5 * Copyright (C) 1995-2009, Rene Brun and Fons Rademakers. *
6 * All rights reserved. *
7 * *
8 * For the licensing terms see $ROOTSYS/LICENSE. *
9 * For the list of contributors see $ROOTSYS/README/CREDITS. *
10 *************************************************************************/
11
12#include <algorithm>
13#include <limits>
14#include <memory>
15#include <vector>
16
17#include "TPadPainter.h"
18#include "TVirtualX.h"
19#include "TCanvas.h"
20#include "TPoint.h"
21#include "TError.h"
22#include "TImage.h"
23#include "TROOT.h"
24#include "TMath.h"
25#include "TPad.h"
26
27namespace {
28
29//Typedef is fine, but let's pretend we look cool and modern:
30using size_type = std::vector<TPoint>::size_type;
31
32template<typename T>
33void ConvertPoints(TVirtualPad *pad, unsigned nPoints, const T *xs, const T *ys,
34 std::vector<TPoint> &dst);
35inline
36void MergePointsX(std::vector<TPoint> &points, unsigned nMerged, SCoord_t yMin,
37 SCoord_t yMax, SCoord_t yLast);
38
39inline
40size_type MergePointsInplaceY(std::vector<TPoint> &dst, size_type nMerged, SCoord_t xMin,
41 SCoord_t xMax, SCoord_t xLast, size_type first);
42
43template<typename T>
44void ConvertPointsAndMergePassX(TVirtualPad *pad, unsigned nPoints, const T *x, const T *y,
45 std::vector<TPoint> &dst);
46
47void ConvertPointsAndMergeInplacePassY(std::vector<TPoint> &dst);
48
49template<class T>
50void DrawFillAreaAux(TVirtualPad *pad, WinContext_t cont, Int_t nPoints, const T *xs, const T *ys, Bool_t add_first_point);
51
52template<typename T>
53void DrawPolyLineAux(TVirtualPad *pad, WinContext_t cont, unsigned nPoints, const T *xs, const T *ys);
54
55template<class T>
56void DrawPolyMarkerAux(TVirtualPad *pad, WinContext_t cont, Bool_t double_buffer, unsigned nPoints, const T *xs, const T *ys);
57
58
59}
60
61
62/** \class TPadPainter
63\ingroup gpad
64
65Implement TVirtualPadPainter which abstracts painting operations.
66*/
67
68////////////////////////////////////////////////////////////////////////////////
69///Empty ctor. We need it only because of explicit copy ctor.
70
76
77/*
78Line/fill/etc. attributes can be set inside TPad, but not only where:
79many of them are set by base sub-objects of 2d primitives
80(2d primitives usually inherit TAttLine or TAttFill etc.). And these sub-objects
81call gVirtualX->SetLineWidth ... etc. So, if I save some attributes in my painter,
82it will be mess - at any moment I do not know, where to take line attribute - from
83gVirtualX or from my own member. So! All attributed, _ALL_ go to/from gVirtualX.
84*/
85
86
87////////////////////////////////////////////////////////////////////////////////
88/// Delegate to gVirtualX.
89
91{
92 gVirtualX->SetOpacityW(fWinContext, percent);
93}
94
95////////////////////////////////////////////////////////////////////////////////
96/// Delegate to gVirtualX.
97
99{
100 return gVirtualX->GetTextMagnitude();
101}
102
103////////////////////////////////////////////////////////////////////////////////
104/// Create a gVirtualX Pixmap.
105
107{
108 return gVirtualX->OpenPixmap(Int_t(w), Int_t(h));
109}
110
111////////////////////////////////////////////////////////////////////////////////
112/// Resize a gVirtualX Pixmap.
113
115{
116 return gVirtualX->ResizePixmap(device, w, h);
117}
118
119
120////////////////////////////////////////////////////////////////////////////////
121/// Returns true when cocoa backend is used
122
124{
125 return gVirtualX->InheritsFrom("TGCocoa");
126}
127
128////////////////////////////////////////////////////////////////////////////////
129/// Returns true if trasnparent colors are supported
130
132{
133 return gVirtualX->InheritsFrom("TGQuartz");
134}
135
136////////////////////////////////////////////////////////////////////////////////
137/// Clear the current gVirtualX window - calling gVirtualX->ClearWindowW
138
140{
141 if (fWinContext)
142 gVirtualX->ClearWindowW(fWinContext);
143}
144
145////////////////////////////////////////////////////////////////////////////////
146/// Clear specified window - calling gVirtualX->ClearWindowW
147
149{
150 auto ctxt = gVirtualX->GetWindowContext(device);
151 if (ctxt)
152 gVirtualX->ClearWindowW(ctxt);
153}
154
155////////////////////////////////////////////////////////////////////////////////
156/// Copy a gVirtualX pixmap.
157
159{
160 gVirtualX->CopyPixmapW(fWinContext, device, px, py);
161}
162
163////////////////////////////////////////////////////////////////////////////////
164/// Close the current gVirtualX pixmap.
165
167{
168 gVirtualX->SelectWindow(device);
169 gVirtualX->ClosePixmap();
171}
172
173////////////////////////////////////////////////////////////////////////////////
174/// Select the window in which the graphics will go.
175
177{
178 gVirtualX->SelectWindow(device);
179 fWinContext = gVirtualX->GetWindowContext(device);
180}
181
182////////////////////////////////////////////////////////////////////////////////
183/// Call low-level update of selected drawable, redirect to gVirtualX.
184
186{
187 gVirtualX->UpdateWindowW(fWinContext, mode);
188}
189
190////////////////////////////////////////////////////////////////////////////////
191/// Set drawing mode for specified device
192
194{
195 gVirtualX->SetDrawModeW(gVirtualX->GetWindowContext(device), (TVirtualX::EDrawMode) mode);
196}
197
198////////////////////////////////////////////////////////////////////////////////
199/// Set double buffer mode for specified device
200
202{
203 // important flag - when disabled canvas pixmap used directly
204 // so one need to use absolute coordinates
205 fDoubleBuffer = mode;
206
207 gVirtualX->SetDoubleBuffer(device, mode);
208}
209
210////////////////////////////////////////////////////////////////////////////////
211///Noop, for non-gl pad TASImage calls gVirtualX->CopyArea.
212
213void TPadPainter::DrawPixels(const unsigned char * /*pixelData*/, UInt_t /*width*/, UInt_t /*height*/,
214 Int_t /*dstX*/, Int_t /*dstY*/, Bool_t /*enableAlphaBlending*/)
215{
216}
217
218////////////////////////////////////////////////////////////////////////////////
219/// Set fill attributes
220
222{
224
226
227 gVirtualX->SetAttFill(fWinContext, fill);
228}
229
230////////////////////////////////////////////////////////////////////////////////
231/// Set line attributes
232
234{
236
237 gVirtualX->SetAttLine(fWinContext, att);
238}
239
240////////////////////////////////////////////////////////////////////////////////
241/// Set marker attributes
242
244{
246
247 gVirtualX->SetAttMarker(fWinContext, att);
248}
249
250////////////////////////////////////////////////////////////////////////////////
251/// Set text attributes
252
254{
256
257 // TODO: in ROOT7 move text size handling directly to correspondent PS engine
258 // One not need to recalculate text size many time back and forth
259
260 if (!fPad)
261 Fatal("SetAttText", "Pad not specified");
262
263 TAttText attm(att);
265
266 gVirtualX->SetAttText(fWinContext, attm);
267}
268
269////////////////////////////////////////////////////////////////////////////////
270/// Paint a simple line.
271
273{
274 if (fAttLine.GetLineWidth() <= 0)
275 return;
276
277 const Int_t px1 = fDoubleBuffer ? gPad->XtoPixel(x1) : gPad->XtoAbsPixel(x1);
278 const Int_t px2 = fDoubleBuffer ? gPad->XtoPixel(x2) : gPad->XtoAbsPixel(x2);
279 const Int_t py1 = fDoubleBuffer ? gPad->YtoPixel(y1) : gPad->YtoAbsPixel(y1);
280 const Int_t py2 = fDoubleBuffer ? gPad->YtoPixel(y2) : gPad->YtoAbsPixel(y2);
281 gVirtualX->DrawLineW(fWinContext, px1, py1, px2, py2);
282}
283
284
285////////////////////////////////////////////////////////////////////////////////
286/// Paint a simple line in normalized coordinates.
287
289{
290 if (fAttLine.GetLineWidth() <= 0)
291 return;
292
293 const Int_t px1 = fDoubleBuffer ? gPad->UtoPixel(u1) : gPad->UtoAbsPixel(u1);
294 const Int_t py1 = fDoubleBuffer ? gPad->VtoPixel(v1) : gPad->VtoAbsPixel(v1);
295 const Int_t px2 = fDoubleBuffer ? gPad->UtoPixel(u2) : gPad->UtoAbsPixel(u2);
296 const Int_t py2 = fDoubleBuffer ? gPad->VtoPixel(v2) : gPad->VtoAbsPixel(v2);
297 gVirtualX->DrawLineW(fWinContext, px1, py1, px2, py2);
298}
299
300
301////////////////////////////////////////////////////////////////////////////////
302/// Paint a simple box.
303
305{
306 if (fAttLine.GetLineWidth() <= 0 && mode == TVirtualPadPainter::kHollow)
307 return;
308
310 return;
311
312 Int_t px1 = fDoubleBuffer ? gPad->XtoPixel(x1) : gPad->XtoAbsPixel(x1);
313 Int_t px2 = fDoubleBuffer ? gPad->XtoPixel(x2) : gPad->XtoAbsPixel(x2);
314 Int_t py1 = fDoubleBuffer ? gPad->YtoPixel(y1) : gPad->YtoAbsPixel(y1);
315 Int_t py2 = fDoubleBuffer ? gPad->YtoPixel(y2) : gPad->YtoAbsPixel(y2);
316
317 // Box width must be at least one pixel (WTF is this code???)
318 if (TMath::Abs(px2 - px1) < 1)
319 px2 = px1 + 1;
320 if (TMath::Abs(py1 - py2) < 1)
321 py1 = py2 + 1;
322
323 gVirtualX->DrawBoxW(fWinContext, px1, py1, px2, py2, (TVirtualX::EBoxMode)mode);
324}
325
326////////////////////////////////////////////////////////////////////////////////
327/// Paint filled area.
328
329void TPadPainter::DrawFillArea(Int_t nPoints, const Double_t *xs, const Double_t *ys)
330{
331 if (nPoints < 3) {
332 ::Error("TPadPainter::DrawFillArea", "invalid number of points %d", nPoints);
333 return;
334 }
335
336 // if fully transparent, add first point to draw line
337 DrawFillAreaAux(gPad, fWinContext, nPoints, xs, ys, fFullyTransparent);
338}
339
340
341////////////////////////////////////////////////////////////////////////////////
342/// Paint filled area.
343
344void TPadPainter::DrawFillArea(Int_t nPoints, const Float_t *xs, const Float_t *ys)
345{
346 if (nPoints < 3) {
347 ::Error("TPadPainter::DrawFillArea", "invalid number of points %d", nPoints);
348 return;
349 }
350
351 // if fully transparent, add first point to draw line
352 DrawFillAreaAux(gPad, fWinContext, nPoints, xs, ys, fFullyTransparent);
353}
354
355////////////////////////////////////////////////////////////////////////////////
356/// Paint Polyline.
357
359{
360 if (fAttLine.GetLineWidth() <= 0)
361 return;
362
363 if (n < 2) {
364 ::Error("TPadPainter::DrawPolyLine", "invalid number of points");
365 return;
366 }
367
368 DrawPolyLineAux(gPad, fWinContext, n, xs, ys);
369}
370
371
372////////////////////////////////////////////////////////////////////////////////
373/// Paint polyline.
374
376{
377 if (fAttLine.GetLineWidth() <= 0)
378 return;
379
380 if (n < 2) {
381 ::Error("TPadPainter::DrawPolyLine", "invalid number of points");
382 return;
383 }
384
385 DrawPolyLineAux(gPad, fWinContext, n, xs, ys);
386}
387
388
389////////////////////////////////////////////////////////////////////////////////
390/// Paint polyline in normalized coordinates.
391
393{
394 if (fAttLine.GetLineWidth() <= 0)
395 return;
396
397 if (n < 2) {
398 ::Error("TPadPainter::DrawPolyLineNDC", "invalid number of points %d", n);
399 return;
400 }
401
402 std::vector<TPoint> xy(n);
403
404 for (Int_t i = 0; i < n; ++i) {
405 xy[i].fX = (SCoord_t)gPad->UtoPixel(u[i]);
406 xy[i].fY = (SCoord_t)gPad->VtoPixel(v[i]);
407 }
408
409 gVirtualX->DrawPolyLineW(fWinContext, n, &xy[0]);
410}
411
412////////////////////////////////////////////////////////////////////////////////
413/// Paint N segments on the pad
414
416{
417 if (fAttLine.GetLineWidth() <= 0)
418 return;
419
420 if (n < 1) {
421 ::Error("TPadPainter::DrawSegments", "invalid number of segments %d", n);
422 return;
423 }
424
425 std::vector<TPoint> xy(n*2);
426 Int_t cnt = 0;
427 for (Int_t i = 0; i < n*2; ++i) {
428 if ((i % 2 == 0) && (x[i] == x[i+1]) && (y[i] == y[i+1])) {
429 // exclude empty segment
430 i++;
431 continue;
432 }
433
434 xy[cnt].fX = (SCoord_t)gPad->XtoPixel(x[i]);
435 xy[cnt].fY = (SCoord_t)gPad->YtoPixel(y[i]);
436 cnt++;
437 }
438
439 if (cnt > 1)
440 gVirtualX->DrawLinesSegmentsW(fWinContext, cnt/2, &xy[0]);
441}
442
443////////////////////////////////////////////////////////////////////////////////
444/// Paint N segments in normalized coordinates on the pad
445
447{
448 if (fAttLine.GetLineWidth() <= 0)
449 return;
450
451 if (n < 1) {
452 ::Error("TPadPainter::DrawSegmentsNDC", "invalid number of segments %d", n);
453 return;
454 }
455
456 std::vector<TPoint> xy(n*2);
457 Int_t cnt = 0;
458 for (Int_t i = 0; i < n*2; ++i) {
459 if ((i % 2 == 0) && (u[i] == u[i+1]) && (v[i] == v[i+1])) {
460 // exclude empty segment
461 i++;
462 continue;
463 }
464
465 xy[cnt].fX = (SCoord_t)gPad->UtoPixel(u[i]);
466 xy[cnt].fY = (SCoord_t)gPad->VtoPixel(v[i]);
467 cnt++;
468 }
469
470 if (cnt > 1)
471 gVirtualX->DrawLinesSegmentsW(fWinContext, cnt/2, &xy[0]);
472}
473
474
475
476////////////////////////////////////////////////////////////////////////////////
477/// Paint polymarker.
478
480{
481 if (n < 1) {
482 ::Error("TPadPainter::DrawPolyMarker", "invalid number of points %d", n);
483 return;
484 }
485
486 DrawPolyMarkerAux(gPad, fWinContext, fDoubleBuffer, n, x, y);
487}
488
489
490////////////////////////////////////////////////////////////////////////////////
491/// Paint polymarker.
492
494{
495 if (n < 1) {
496 ::Error("TPadPainter::DrawPolyMarker", "invalid number of points %d", n);
497 return;
498 }
499
500 DrawPolyMarkerAux(gPad, fWinContext, fDoubleBuffer, n, x, y);
501}
502
503
504////////////////////////////////////////////////////////////////////////////////
505/// Paint text.
506
508{
509 const Int_t px = gPad->XtoPixel(x);
510 const Int_t py = gPad->YtoPixel(y);
511 const Double_t angle = GetTextAngle();
512 const Double_t mgn = GetTextMagnitude();
513 gVirtualX->DrawTextW(fWinContext, px, py, angle, mgn, text, (TVirtualX::ETextMode)mode);
514}
515
516
517////////////////////////////////////////////////////////////////////////////////
518/// Special version working with wchar_t and required by TMathText.
519
521{
522 const Int_t px = gPad->XtoPixel(x);
523 const Int_t py = gPad->YtoPixel(y);
524 const Double_t angle = GetTextAngle();
525 const Double_t mgn = GetTextMagnitude();
526 gVirtualX->DrawTextW(fWinContext, px, py, angle, mgn, text, (TVirtualX::ETextMode)mode);
527}
528
529
530////////////////////////////////////////////////////////////////////////////////
531/// Paint text in normalized coordinates.
532
534{
535 const Int_t px = gPad->UtoPixel(u);
536 const Int_t py = gPad->VtoPixel(v);
537 const Double_t angle = GetTextAngle();
538 const Double_t mgn = GetTextMagnitude();
539 gVirtualX->DrawTextW(fWinContext, px, py, angle, mgn, text, (TVirtualX::ETextMode)mode);
540}
541
542
543////////////////////////////////////////////////////////////////////////////////
544/// Save the image displayed in the canvas pointed by "pad" into a binary file.
545
546void TPadPainter::SaveImage(TVirtualPad *pad, const char *fileName, Int_t type) const
547{
548 if (gVirtualX->InheritsFrom("TGCocoa") && !gROOT->IsBatch() &&
549 pad->GetCanvas() && pad->GetCanvas()->GetCanvasID() != -1) {
550
551 TCanvas * const canvas = pad->GetCanvas();
552 //Force TCanvas::CopyPixmaps.
553 canvas->Flush();
554
555 const UInt_t w = canvas->GetWw();
556 const UInt_t h = canvas->GetWh();
557
558 const std::unique_ptr<unsigned char[]>
559 pixelData(gVirtualX->GetColorBits(canvas->GetCanvasID(), 0, 0, w, h));
560
561 if (pixelData.get()) {
562 const std::unique_ptr<TImage> image(TImage::Create());
563 if (image.get()) {
564 image->DrawRectangle(0, 0, w, h);
565 if (unsigned char *argb = (unsigned char *)image->GetArgbArray()) {
566 //Ohhh.
567 if (sizeof(UInt_t) == 4) {
568 //For sure the data returned from TGCocoa::GetColorBits,
569 //it's 4 * w * h bytes with what TASImage considers to be argb.
570 std::copy(pixelData.get(), pixelData.get() + 4 * w * h, argb);
571 } else {
572 //A bit paranoid, don't you think so?
573 //Will Quartz/TASImage work at all on such a fancy platform? ;)
574 const unsigned shift = std::numeric_limits<unsigned char>::digits;
575 //
576 unsigned *dstPixel = (unsigned *)argb, *end = dstPixel + w * h;
577 const unsigned char *srcPixel = pixelData.get();
578 for (;dstPixel != end; ++dstPixel, srcPixel += 4) {
579 //Looks fishy but should work, trust me :)
580 *dstPixel = srcPixel[0] & (srcPixel[1] << shift) &
581 (srcPixel[2] << 2 * shift) &
582 (srcPixel[3] << 3 * shift);
583 }
584 }
585
586 image->WriteImage(fileName, (TImage::EImageFileTypes)type);
587 //Success.
588 return;
589 }
590 }
591 }
592 }
593
594 if (type == TImage::kGif) {
595 Int_t wid = (pad == pad->GetCanvas()) ? pad->GetCanvasID() : pad->GetPixmapID();
596 auto ctxt = gVirtualX->GetWindowContext(wid);
597 // TODO: if fail, one can use TImage functionality instead
598 gVirtualX->WriteGIFW(ctxt, fileName);
599 } else {
600 const std::unique_ptr<TImage> img(TImage::Create());
601 if (img.get()) {
602 img->FromPad(pad);
603 img->WriteImage(fileName, (TImage::EImageFileTypes)type);
604 }
605 }
606}
607
608
609////////////////////////////////////////////////////////////////////////////////
610/// Paint text in normalized coordinates.
611
613{
614 const Int_t px = gPad->UtoPixel(u);
615 const Int_t py = gPad->VtoPixel(v);
616 const Double_t angle = GetTextAngle();
617 const Double_t mgn = GetTextMagnitude();
618 gVirtualX->DrawTextW(fWinContext, px, py, angle, mgn, text, (TVirtualX::ETextMode)mode);
619}
620
621//Aux. private functions.
622namespace {
623
624////////////////////////////////////////////////////////////////////////////////
625///I'm using 'pad' pointer to get rid of this damned gPad.
626///Unfortunately, TPadPainter itself still has to use it.
627///But at least this code does not have to be fixed.
628
629template<typename T>
630void ConvertPoints(TVirtualPad *pad, unsigned nPoints, const T *x, const T *y,
631 std::vector<TPoint> &dst)
632{
633 if (!nPoints)
634 return;
635
636 dst.resize(nPoints);
637
638 for (unsigned i = 0; i < nPoints; ++i) {
639 dst[i].fX = (SCoord_t)pad->XtoPixel(x[i]);
640 dst[i].fY = (SCoord_t)pad->YtoPixel(y[i]);
641 }
642}
643
644////////////////////////////////////////////////////////////////////////////////
645
646inline void MergePointsX(std::vector<TPoint> &points, unsigned nMerged, SCoord_t yMin,
647 SCoord_t yMax, SCoord_t yLast)
648{
649 const auto firstPointX = points.back().fX;
650 const auto firstPointY = points.back().fY;
651
652 if (nMerged == 2) {
653 points.push_back(TPoint(firstPointX, yLast));//We have not merge anything.
654 } else if (nMerged == 3) {
655 yMin == firstPointY ? points.push_back(TPoint(firstPointX, yMax)) :
656 points.push_back(TPoint(firstPointX, yMin));
657 points.push_back(TPoint(firstPointX, yLast));
658 } else {
659 points.push_back(TPoint(firstPointX, yMin));
660 points.push_back(TPoint(firstPointX, yMax));
661 points.push_back(TPoint(firstPointX, yLast));
662 }
663}
664
665////////////////////////////////////////////////////////////////////////////////
666///Indices below are _valid_.
667
668inline size_type MergePointsInplaceY(std::vector<TPoint> &dst, size_type nMerged, SCoord_t xMin,
669 SCoord_t xMax, SCoord_t xLast, size_type first)
670{
671 const TPoint &firstPoint = dst[first];//This point is never updated.
672
673 if (nMerged == 2) {
674 dst[first + 1].fX = xLast;
675 dst[first + 1].fY = firstPoint.fY;
676 } else if (nMerged == 3) {
677 dst[first + 1].fX = xMin == firstPoint.fX ? xMax : xMin;
678 dst[first + 1].fY = firstPoint.fY;
679 dst[first + 2].fX = xLast;
680 dst[first + 2].fY = firstPoint.fY;
681 } else {
682 dst[first + 1].fX = xMin;
683 dst[first + 1].fY = firstPoint.fY;
684 dst[first + 2].fX = xMax;
685 dst[first + 2].fY = firstPoint.fY;
686 dst[first + 3].fX = xLast;
687 dst[first + 3].fY = firstPoint.fY;
688 nMerged = 4;//Adjust the shift.
689 }
690
691 return nMerged;
692}
693
694////////////////////////////////////////////////////////////////////////////////
695/// I'm using 'pad' pointer to get rid of this damned gPad.
696/// Unfortunately, TPadPainter itself still has to use it.
697/// But at least this code does not have to be fixed.
698
699template<typename T>
700void ConvertPointsAndMergePassX(TVirtualPad *pad, unsigned nPoints, const T *x, const T *y,
701 std::vector<TPoint> &dst)
702{
703 //The "first" pass along X axis.
704 TPoint currentPoint;
705 SCoord_t yMin = 0, yMax = 0, yLast = 0;
706 unsigned nMerged = 0;
707
708 //The first pass along X.
709 for (unsigned i = 0; i < nPoints;) {
710 currentPoint.fX = (SCoord_t)pad->XtoPixel(x[i]);
711 currentPoint.fY = (SCoord_t)pad->YtoPixel(y[i]);
712
713 yMin = currentPoint.fY;
714 yMax = yMin;
715
716 dst.push_back(currentPoint);
717 bool merged = false;
718 nMerged = 1;
719
720 for (unsigned j = i + 1; j < nPoints; ++j) {
721 const SCoord_t newX = pad->XtoPixel(x[j]);
722
723 if (newX == currentPoint.fX) {
724 yLast = pad->YtoPixel(y[j]);
725 yMin = TMath::Min(yMin, yLast);
726 yMax = TMath::Max(yMax, yLast);//We continue.
727 ++nMerged;
728 } else {
729 if (nMerged > 1)
730 MergePointsX(dst, nMerged, yMin, yMax, yLast);
731 merged = true;
732 break;
733 }
734 }
735
736 if (!merged && nMerged > 1)
737 MergePointsX(dst, nMerged, yMin, yMax, yLast);
738
739 i += nMerged;
740 }
741}
742
743////////////////////////////////////////////////////////////////////////////////
744/// This pass is a bit more complicated, since we have to 'compact' in-place.
745
746void ConvertPointsAndMergeInplacePassY(std::vector<TPoint> &dst)
747{
748 size_type i = 0;
749 for (size_type j = 1, nPoints = dst.size(); i < nPoints;) {
750 //i is always less than j, so i is always valid here.
751 const TPoint &currentPoint = dst[i];
752
753 SCoord_t xMin = currentPoint.fX;
754 SCoord_t xMax = xMin;
755 SCoord_t xLast = 0;
756
757 bool merged = false;
758 size_type nMerged = 1;
759
760 for (; j < nPoints; ++j) {
761 const TPoint &nextPoint = dst[j];
762
763 if (nextPoint.fY == currentPoint.fY) {
764 xLast = nextPoint.fX;
765 xMin = TMath::Min(xMin, xLast);
766 xMax = TMath::Max(xMax, xLast);
767 ++nMerged;//and we continue ...
768 } else {
769 if (nMerged > 1)
770 nMerged = MergePointsInplaceY(dst, nMerged, xMin, xMax, xLast, i);
771 merged = true;
772 break;
773 }
774 }
775
776 if (!merged && nMerged > 1)
777 nMerged = MergePointsInplaceY(dst, nMerged, xMin, xMax, xLast, i);
778
779 i += nMerged;
780
781 if (j < nPoints) {
782 dst[i] = dst[j];
783 ++j;
784 } else
785 break;
786 }
787
788 dst.resize(i);
789}
790
791////////////////////////////////////////////////////////////////////////////////
792/// This is a quite simple algorithm, using the fact, that after conversion many
793/// subsequent vertices can have the same 'x' or 'y' coordinate and this part of
794/// a polygon will look like a line on the screen.
795
796template<typename T>
797void ConvertPointsAndMerge(TVirtualPad *pad, unsigned threshold, unsigned nPoints, const T *x,
798 const T *y, std::vector<TPoint> &dst)
799{
800 //I'm using 'pad' pointer to get rid of this damned gPad.
801 //Unfortunately, TPadPainter itself still has to use it.
802 //But at least this code does not have to be fixed.
803
804 if (!nPoints)
805 return;
806
807 dst.clear();
808 dst.reserve(threshold);
809
810 ConvertPointsAndMergePassX(pad, nPoints, x, y, dst);
811
812 if (dst.size() < threshold)
813 return;
814
815 ConvertPointsAndMergeInplacePassY(dst);
816}
817
818////////////////////////////////////////////////////////////////////////////////
819
820template<class T>
821void DrawFillAreaAux(TVirtualPad *pad, WinContext_t cont, Int_t nPoints, const T *xs, const T *ys, Bool_t add_first_point)
822{
823 std::vector<TPoint> xy;
824
825 const Int_t threshold = Int_t(TMath::Min(pad->GetWw() * pad->GetAbsWNDC(),
826 pad->GetWh() * pad->GetAbsHNDC())) * 2;
827
828 if (threshold <= 0) {
829 //Ooops, pad is invisible or something really bad and stupid happened.
830 ::Error("DrawFillAreaAux", "invalid pad's geometry");
831 return;
832 }
833
834 if (nPoints < threshold)
835 ConvertPoints(pad, nPoints, xs, ys, xy);
836 else
837 ConvertPointsAndMerge(pad, threshold, nPoints, xs, ys, xy);
838
839 //We close the 'polygon' so it can be rendered as a polyline by gVirtualX.
840 if (add_first_point)
841 xy.push_back(xy.front());
842
843 if (xy.size() > 2)
844 gVirtualX->DrawFillAreaW(cont, xy.size(), xy.data());
845}
846
847////////////////////////////////////////////////////////////////////////////////
848
849template<typename T>
850void DrawPolyLineAux(TVirtualPad *pad, WinContext_t cont, unsigned nPoints, const T *xs, const T *ys)
851{
852 std::vector<TPoint> xy;
853
854 const Int_t threshold = Int_t(TMath::Min(pad->GetWw() * pad->GetAbsWNDC(),
855 pad->GetWh() * pad->GetAbsHNDC())) * 2;
856
857 if (threshold <= 0) {//Ooops, pad is invisible or something really bad and stupid happened.
858 ::Error("DrawPolyLineAux", "invalid pad's geometry");
859 return;
860 }
861
862 if (nPoints < (unsigned)threshold)
863 ConvertPoints(pad, nPoints, xs, ys, xy);
864 else
865 ConvertPointsAndMerge(pad, threshold, nPoints, xs, ys, xy);
866
867 if (xy.size() > 1)
868 gVirtualX->DrawPolyLineW(cont, xy.size(), &xy[0]);
869
870}
871
872////////////////////////////////////////////////////////////////////////////////
873
874template<class T>
875void DrawPolyMarkerAux(TVirtualPad *pad, WinContext_t cont, Bool_t double_buffer, unsigned nPoints, const T *xs, const T *ys)
876{
877 std::vector<TPoint> xy(nPoints);
878
879 for (unsigned i = 0; i < nPoints; ++i) {
880 xy[i].fX = (SCoord_t) (double_buffer ? pad->XtoPixel(xs[i]) : pad->XtoAbsPixel(xs[i]));
881 xy[i].fY = (SCoord_t) (double_buffer ? pad->YtoPixel(ys[i]) : pad->YtoAbsPixel(ys[i]));
882 }
883
884 gVirtualX->DrawPolyMarkerW(cont, nPoints, &xy[0]);
885}
886
887}
Handle_t WinContext_t
Window drawing context.
Definition GuiTypes.h:30
#define h(i)
Definition RSha256.hxx:106
int Int_t
Signed integer 4 bytes (int).
Definition RtypesCore.h:59
unsigned int UInt_t
Unsigned integer 4 bytes (unsigned int).
Definition RtypesCore.h:60
bool Bool_t
Boolean (0=false, 1=true) (bool).
Definition RtypesCore.h:77
double Double_t
Double 8 bytes.
Definition RtypesCore.h:73
short SCoord_t
Screen coordinates (short).
Definition RtypesCore.h:100
float Float_t
Float 4 bytes (float).
Definition RtypesCore.h:71
Error("WriteTObject","The current directory (%s) is not associated with a file. The object (%s) has not been written.", GetName(), objname)
void Fatal(const char *location, const char *msgfmt,...)
Use this function in case of a fatal error. It will abort the program.
Definition TError.cxx:267
#define gROOT
Definition TROOT.h:417
#define gPad
#define gVirtualX
Definition TVirtualX.h:375
point * points
Definition X3DBuffer.c:22
virtual Float_t GetTextSizePixels(TVirtualPad &pad) const
Return the text size in pixels for specified pad.
virtual void SetTextSize(Float_t tsize=1)
Set the text size.
Definition TAttText.h:53
The Canvas class.
Definition TCanvas.h:23
Int_t GetCanvasID() const override
Definition TCanvas.h:161
UInt_t GetWw() const override
Definition TCanvas.h:167
UInt_t GetWh() const override
Definition TCanvas.h:168
void Flush()
Flush canvas buffers.
Definition TCanvas.cxx:1141
EImageFileTypes
Definition TImage.h:36
@ kGif
Definition TImage.h:48
static TImage * Create()
Create an image.
Definition TImage.cxx:34
void SetAttFill(const TAttFill &att) override
Set fill attributes.
void SetAttText(const TAttText &att) override
Set text attributes.
TAttLine fAttLine
current line attributes
Bool_t fFullyTransparent
if transformed fill attributes fully transparent
void SetAttMarker(const TAttMarker &att) override
Set marker attributes.
void SetAttLine(const TAttLine &att) override
Set line attributes.
Float_t GetTextAngle() const override
TAttFill GetAttFillInternal(Bool_t with_transparency)
Returns fill attributes after modification Checks for special fill styles 4000 .
void DrawSegments(Int_t n, Double_t *x, Double_t *y) override
Paint N segments on the pad.
TPadPainter()
Empty ctor. We need it only because of explicit copy ctor.
void DrawFillArea(Int_t n, const Double_t *x, const Double_t *y) override
Paint filled area.
void SetAttText(const TAttText &att) override
Set text attributes.
void DrawPixels(const unsigned char *pixelData, UInt_t width, UInt_t height, Int_t dstX, Int_t dstY, Bool_t enableAlphaBlending) override
Noop, for non-gl pad TASImage calls gVirtualX->CopyArea.
void UpdateDrawable(Int_t mode) override
Call low-level update of selected drawable, redirect to gVirtualX.
void CopyDrawable(Int_t device, Int_t px, Int_t py) override
Copy a gVirtualX pixmap.
void SetAttMarker(const TAttMarker &att) override
Set marker attributes.
void DrawPolyLine(Int_t n, const Double_t *x, const Double_t *y) override
Paint Polyline.
Int_t fDoubleBuffer
Definition TPadPainter.h:27
Int_t ResizeDrawable(Int_t device, UInt_t w, UInt_t h) override
Resize a gVirtualX Pixmap.
Float_t GetTextMagnitude() const override
Delegate to gVirtualX.
Bool_t IsSupportAlpha() const override
Returns true if trasnparent colors are supported.
void ClearWindow(Int_t device) override
Clear specified window - calling gVirtualX->ClearWindowW.
Int_t CreateDrawable(UInt_t w, UInt_t h) override
Create a gVirtualX Pixmap.
void SetAttFill(const TAttFill &att) override
Set fill attributes.
void DrawPolyMarker(Int_t n, const Double_t *x, const Double_t *y) override
Paint polymarker.
void SetOpacity(Int_t percent) override
Delegate to gVirtualX.
void DrawTextNDC(Double_t u, Double_t v, const char *text, ETextMode mode) override
Paint text in normalized coordinates.
Bool_t IsCocoa() const override
Returns true when cocoa backend is used.
void SaveImage(TVirtualPad *pad, const char *fileName, Int_t type) const override
Save the image displayed in the canvas pointed by "pad" into a binary file.
void DrawPolyLineNDC(Int_t n, const Double_t *u, const Double_t *v) override
Paint polyline in normalized coordinates.
void SetDrawMode(Int_t device, Int_t mode) override
Set drawing mode for specified device.
void ClearDrawable() override
Clear the current gVirtualX window - calling gVirtualX->ClearWindowW.
void DestroyDrawable(Int_t device) override
Close the current gVirtualX pixmap.
WinContext_t fWinContext
Definition TPadPainter.h:26
TVirtualPad * fPad
Definition TPadPainter.h:28
void DrawSegmentsNDC(Int_t n, Double_t *u, Double_t *v) override
Paint N segments in normalized coordinates on the pad.
void SetAttLine(const TAttLine &att) override
Set line attributes.
void SelectDrawable(Int_t device) override
Select the window in which the graphics will go.
void DrawBox(Double_t x1, Double_t y1, Double_t x2, Double_t y2, EBoxMode mode) override
Paint a simple box.
void DrawLine(Double_t x1, Double_t y1, Double_t x2, Double_t y2) override
Paint a simple line.
void DrawLineNDC(Double_t u1, Double_t v1, Double_t u2, Double_t v2) override
Paint a simple line in normalized coordinates.
void DrawText(Double_t x, Double_t y, const char *text, ETextMode mode) override
Paint text.
void SetDoubleBuffer(Int_t device, Int_t mode) override
Set double buffer mode for specified device.
SCoord_t fY
Definition TPoint.h:36
SCoord_t fX
Definition TPoint.h:35
TVirtualPad is an abstract base class for the Pad and Canvas classes.
Definition TVirtualPad.h:51
virtual Int_t YtoAbsPixel(Double_t y) const =0
virtual Int_t YtoPixel(Double_t y) const =0
virtual UInt_t GetWh() const =0
virtual Int_t XtoAbsPixel(Double_t x) const =0
virtual Int_t GetPixmapID() const =0
virtual Double_t GetAbsWNDC() const =0
virtual Double_t GetAbsHNDC() const =0
virtual Int_t XtoPixel(Double_t x) const =0
virtual UInt_t GetWw() const =0
virtual Int_t GetCanvasID() const =0
virtual TCanvas * GetCanvas() const =0
TText * text
Double_t y[n]
Definition legend1.C:17
Double_t x[n]
Definition legend1.C:17
const Int_t n
Definition legend1.C:16
Short_t Max(Short_t a, Short_t b)
Returns the largest of a and b.
Definition TMathBase.h:249
Short_t Min(Short_t a, Short_t b)
Returns the smallest of a and b.
Definition TMathBase.h:197
Short_t Abs(Short_t d)
Returns the absolute value of parameter Short_t d.
Definition TMathBase.h:122