Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit 1261a30

Browse files
committed
Fix additional misalignments due to numerical precision
There are multiple instances where a value that would ideally be exactly at a half display pixel might instead be one floating-point tick away in the wrong direction. Here fudge amounts are added so that the rounding occurs in the desired direction. An analogous situation occurs for truncation to a whole pixel. The amount of 1e-8 is chosen because it covers 1e-13 relative error for 100,000 pixels.
1 parent f0fec8b commit 1261a30

2 files changed

Lines changed: 18 additions & 8 deletions

File tree

lib/matplotlib/image.py

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -410,8 +410,12 @@ def _make_image(self, A, in_bbox, out_bbox, clip_bbox, magnification=1.0,
410410
magnified_extents = clipped_bbox.extents * magnification
411411
if ((not unsampled) and round_to_pixel_border):
412412
# Round to the nearest output pixel
413-
x0, x1 = np.floor(magnified_extents[0::2] + 0.5) # round half up
414-
y0, y1 = np.ceil(magnified_extents[1::2] - 0.5) # round half down
413+
# Add a tiny fudge amount to account for numerical precision loss
414+
# on the two sides away from the Agg anchor point (x0, y1)
415+
x0 = np.floor(magnified_extents[0] + 0.5) # round half up
416+
y0 = np.ceil(magnified_extents[1] - 0.5 - 1e-8) # round half down
417+
x1 = np.floor(magnified_extents[2] + 0.5 + 1e-8) # round half up
418+
y1 = np.ceil(magnified_extents[3] - 0.5) # round half down
415419
magnified_bbox = Bbox.from_extents([x0, y0, x1, y1])
416420
else:
417421
magnified_bbox = Bbox.from_extents(magnified_extents)

src/_image_resample.h

Lines changed: 12 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -589,8 +589,9 @@ class lookup_distortion
589589
if (dx >= 0 && dx < m_out_width &&
590590
dy >= 0 && dy < m_out_height) {
591591
const double *coord = m_mesh + (int(dy) * m_out_width + int(dx)) * 2;
592-
*x = int(coord[0] * agg::image_subpixel_scale + offset);
593-
*y = int(coord[1] * agg::image_subpixel_scale + offset);
592+
// Add a tiny fudge amount to account for numerical precision loss
593+
*x = int(coord[0] * agg::image_subpixel_scale + offset + 1e-8);
594+
*y = int(coord[1] * agg::image_subpixel_scale + offset + 1e-8);
594595
}
595596
}
596597
}
@@ -780,10 +781,15 @@ void resample(
780781
params.affine.transform(&right, &top);
781782
if (left > right) { std::swap(left, right); }
782783
if (bottom > top) { std::swap(top, bottom); }
783-
if (round(left) < left) { left = round(left); }
784-
if (round(right) > right) { right = round(right); }
785-
if (round(bottom) < bottom) { bottom = round(bottom); }
786-
if (round(top) > top) { top = round(top); }
784+
// Add a tiny fudge amount to account for numerical precision loss
785+
int rleft = agg::iround(left - 1e-8);
786+
int rright = agg::iround(right + 1e-8);
787+
int rbottom = agg::iround(bottom - 1e-8);
788+
int rtop = agg::iround(top + 1e-8);
789+
if (rleft < left) { left = rleft; }
790+
if (rright > right) { right = rright; }
791+
if (rbottom < bottom) { bottom = rbottom; }
792+
if (rtop > top) { top = rtop; }
787793
path.move_to(left, bottom);
788794
path.line_to(right, bottom);
789795
path.line_to(right, top);

0 commit comments

Comments
 (0)