diff --git a/builtins/libAfterImage/draw.c b/builtins/libAfterImage/draw.c index e4d10bb6fa2b8..cb51ee1e1ae0a 100644 --- a/builtins/libAfterImage/draw.c +++ b/builtins/libAfterImage/draw.c @@ -1523,6 +1523,7 @@ asim_ellips2( ASDrawContext *ctx, int x, int y, int rx, int ry, int angle, Bool { double d ; int dx1 = 0, dx2 = 0 ; + int fill_edge = -1 ; d = A*(double)x1*(double)x1 + BB +CC*(double)x1; #ifdef DEBUG_ELLIPS fprintf( stderr, "line = %d, d1 = %f", y-line, d ); @@ -1634,6 +1635,7 @@ asim_ellips2( ASDrawContext *ctx, int x, int y, int rx, int ry, int angle, Bool dd += aa ; } x2 += (dx2>>1)-1 ; + fill_edge = 1 ; last_med_dd2 = med_dd ; } }else if( line < yr ) @@ -1699,8 +1701,8 @@ asim_ellips2( ASDrawContext *ctx, int x, int y, int rx, int ry, int angle, Bool #endif if( fill ) { - CTX_FILL_HLINE(ctx,x+(x1-2),y-y1,x+x2-1,255); - CTX_FILL_HLINE(ctx,x-x2-1,y+y1,x-(x1-2),255); + CTX_FILL_HLINE(ctx,x+(x1-2),y-y1,x+(x2+fill_edge),255); + CTX_FILL_HLINE(ctx,x-(x2+fill_edge),y+y1,x-(x1-2),255); } CC -= 2.*C ; diff --git a/graf2d/asimage/test/CMakeLists.txt b/graf2d/asimage/test/CMakeLists.txt index 96f1b11a7e0a4..c08327d3e21db 100644 --- a/graf2d/asimage/test/CMakeLists.txt +++ b/graf2d/asimage/test/CMakeLists.txt @@ -5,6 +5,3 @@ # For the list of contributors see $ROOTSYS/README/CREDITS. ROOT_ADD_GTEST(TASImageDraw tasimage_draw.cxx LIBRARIES ASImage) - -# add failing test until fixed -ROOT_ADD_GTEST(TASImageDrawEllipse tasimage_ellipse_draw.cxx WILLFAIL LIBRARIES ASImage) diff --git a/graf2d/asimage/test/tasimage_draw.cxx b/graf2d/asimage/test/tasimage_draw.cxx index 07fd5aa47325c..ca7df1196ba80 100644 --- a/graf2d/asimage/test/tasimage_draw.cxx +++ b/graf2d/asimage/test/tasimage_draw.cxx @@ -169,22 +169,24 @@ TEST(TASImage, FillePolygonLowAlpha) CheckFilledShapeStaysInside("#100000FF", 2); } -/* - -// comment out all ellpse test while they are failing +// https://github.com/root-project/root/issues/23120 +// +// asim_ellips2 walks a tilted ellipse one scanline pair at a time and exploits +// the 180 degree rotational symmetry, so the two spans it fills per iteration +// must mirror each other. The right edge was one pixel short of its partner, +// which left unfilled pixels along the tilted boundary. The point checked below +// sits inside the ellipse and used to stay empty. TEST(TASImage, FilledEllipsOpaque) { CheckFilledShapeStaysInside("#FF2277CC", 3); } -// Used to leak out of the circle and fill the whole image. TEST(TASImage, FilledEllipsHighAlpha) { CheckFilledShapeStaysInside("#C02277CC", 3); } -// Used to hang: the colour from the issue report. TEST(TASImage, FilledEllipsSemiTransparent) { CheckFilledShapeStaysInside("#7F2277CC", 3); @@ -194,4 +196,3 @@ TEST(TASImage, FilleEllipsLowAlpha) { CheckFilledShapeStaysInside("#102277CC", 3); } -*/ diff --git a/graf2d/asimage/test/tasimage_ellipse_draw.cxx b/graf2d/asimage/test/tasimage_ellipse_draw.cxx deleted file mode 100644 index e1c153b539864..0000000000000 --- a/graf2d/asimage/test/tasimage_ellipse_draw.cxx +++ /dev/null @@ -1,116 +0,0 @@ -#include "gtest/gtest.h" - -#include "TASImage.h" -#include "TPoint.h" - -namespace { - -constexpr UInt_t kSize = 64; - -constexpr UInt_t kPixels = kSize * kSize; - -// Index of the four canvas corners. -constexpr UInt_t kCorners[4] = {0, kSize - 1, (kSize - 1) * kSize, kPixels - 1}; - -// Draw a filled shape of `colour` well inside a kSize x kSize image and check -// that the fill stayed inside it. The corner values are compared against what -// they were before drawing rather than against a constant, so the test does not -// depend on how a fresh TASImage is initialised. -// At the end check number of modified pixels comparing with expected value -void CheckFilledShapeStaysInside(const char *colour, Int_t shape) -{ - TASImage img(kSize, kSize); - - UInt_t *argb = img.GetArgbArray(); - ASSERT_NE(argb, nullptr); - - UInt_t before[4]; - for (int i = 0; i < 4; ++i) - before[i] = argb[kCorners[i]]; - const UInt_t centre = (kSize / 2) * kSize + kSize / 2; - const UInt_t centreBefore = argb[centre]; - - float expected_area = 0, expected_delta = 1.; - const char *name = ""; - - std::vector vect; - - switch (shape) { - case 1: - img.FillRectangle(colour, kSize / 4, kSize / 4, kSize / 2, kSize / 2); - name = "Rectangle"; - expected_area = (kSize / 2) * (kSize / 2); - expected_delta = 1; - break; - case 2: - vect.emplace_back(kSize/4, kSize/4); - vect.emplace_back(kSize/4*3, kSize/2); - vect.emplace_back(kSize/4, kSize/4*3); - vect.emplace_back(kSize/2, kSize/2); - img.FillPolygon(vect.size(), vect.data(), colour); - name = "Polygon"; - expected_area = (kSize / 4) * (kSize / 4); - expected_delta = kSize / 4; - break; - case 3: - img.DrawEllips2(kSize / 2, kSize / 2, kSize / 3, kSize / 7, 45, colour, -1); - name = "Ellipse"; - expected_area = 3.1415 * (kSize / 3 + 1) * (kSize / 7 + 1); - expected_delta = kSize / 3 * 3.14; - break; - default: - img.DrawCircle(kSize / 2, kSize / 2, kSize / 4, colour, -1); - name = "Circle"; - expected_area = 3.1415 * (kSize / 4 + 1) * (kSize / 4 + 1); - expected_delta = kSize / 2 * 3.14; - break; - } - - argb = img.GetArgbArray(); - ASSERT_NE(argb, nullptr); - - for (int i = 0; i < 4; ++i) - EXPECT_EQ(argb[kCorners[i]], before[i]) << "the fill escaped the " << name << " and reached corner " << i; - - EXPECT_NE(argb[centre], centreBefore) << "the " << name << " was not filled at all"; - - if (shape == 3) { - // recent bug in the DrawEllips2 - unsigned x = kSize / 2 + kSize / 5 + 1; - unsigned y = kSize / 2 - kSize / 5 - 2; - EXPECT_NE(argb[y * kSize + x], centreBefore) << "the DrawEllips2 does not fill point inside the " << name; - } - - // also check filling status - Int_t fillcnt = 0; - for (UInt_t i = 0; i < kPixels; i++) - if(argb[i] != centreBefore) fillcnt++; - - EXPECT_NEAR(fillcnt, expected_area, expected_delta) << "number of filled " << name << " points too far from expected"; - -} - -} // namespace - - -TEST(TASImage, FilledEllipsOpaque) -{ - CheckFilledShapeStaysInside("#FF2277CC", 3); -} - -// Used to leak out of the circle and fill the whole image. -TEST(TASImage, FilledEllipsHighAlpha) -{ - CheckFilledShapeStaysInside("#C02277CC", 3); -} - -// Used to hang: the colour from the issue report. -TEST(TASImage, FilledEllipsSemiTransparent) -{ - CheckFilledShapeStaysInside("#7F2277CC", 3); -} - -TEST(TASImage, FilleEllipsLowAlpha) -{ - CheckFilledShapeStaysInside("#102277CC", 3); -}