Skip to content

Commit

Permalink
Merge pull request matplotlib#28967 from QuLogic/msvc-casts
Browse files Browse the repository at this point in the history
Fix MSVC cast warnings
  • Loading branch information
ianthomas23 authored Oct 25, 2024
2 parents 6e60725 + 4d40c1b commit 3770dfe
Show file tree
Hide file tree
Showing 9 changed files with 116 additions and 31 deletions.
12 changes: 12 additions & 0 deletions doc/api/next_api_changes/deprecations/28967-ES.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
Passing floating-point values to ``RendererAgg.draw_text_image``
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

Any floating-point values passed to the *x* and *y* parameters were truncated to integers
silently. This behaviour is now deprecated, and only `int` values should be used.

Passing floating-point values to ``FT2Image``
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

Any floating-point values passed to the `.FT2Image` constructor, or the *x0*, *y0*, *x1*,
and *y1* parameters of `.FT2Image.draw_rect_filled` were truncated to integers silently.
This behaviour is now deprecated, and only `int` values should be used.
6 changes: 3 additions & 3 deletions lib/matplotlib/_mathtext.py
Original file line number Diff line number Diff line change
Expand Up @@ -153,7 +153,7 @@ def to_raster(self, *, antialiased: bool) -> RasterParse:
w = xmax - xmin
h = ymax - ymin - self.box.depth
d = ymax - ymin - self.box.height
image = FT2Image(np.ceil(w), np.ceil(h + max(d, 0)))
image = FT2Image(int(np.ceil(w)), int(np.ceil(h + max(d, 0))))

# Ideally, we could just use self.glyphs and self.rects here, shifting
# their coordinates by (-xmin, -ymin), but this yields slightly
Expand All @@ -163,7 +163,7 @@ def to_raster(self, *, antialiased: bool) -> RasterParse:

for ox, oy, info in shifted.glyphs:
info.font.draw_glyph_to_bitmap(
image, ox, oy - info.metrics.iceberg, info.glyph,
image, int(ox), int(oy - info.metrics.iceberg), info.glyph,
antialiased=antialiased)
for x1, y1, x2, y2 in shifted.rects:
height = max(int(y2 - y1) - 1, 0)
Expand All @@ -172,7 +172,7 @@ def to_raster(self, *, antialiased: bool) -> RasterParse:
y = int(center - (height + 1) / 2)
else:
y = int(y1)
image.draw_rect_filled(int(x1), y, np.ceil(x2), y + height)
image.draw_rect_filled(int(x1), y, int(np.ceil(x2)), y + height)
return RasterParse(0, 0, w, h + d, d, image)


Expand Down
6 changes: 3 additions & 3 deletions lib/matplotlib/ft2font.pyi
Original file line number Diff line number Diff line change
Expand Up @@ -198,7 +198,7 @@ class FT2Font(Buffer):
def _get_fontmap(self, string: str) -> dict[str, FT2Font]: ...
def clear(self) -> None: ...
def draw_glyph_to_bitmap(
self, image: FT2Image, x: float, y: float, glyph: Glyph, antialiased: bool = ...
self, image: FT2Image, x: int, y: int, glyph: Glyph, antialiased: bool = ...
) -> None: ...
def draw_glyphs_to_bitmap(self, antialiased: bool = ...) -> None: ...
def get_bitmap_offset(self) -> tuple[int, int]: ...
Expand Down Expand Up @@ -281,8 +281,8 @@ class FT2Font(Buffer):

@final
class FT2Image(Buffer):
def __init__(self, width: float, height: float) -> None: ...
def draw_rect_filled(self, x0: float, y0: float, x1: float, y1: float) -> None: ...
def __init__(self, width: int, height: int) -> None: ...
def draw_rect_filled(self, x0: int, y0: int, x1: int, y1: int) -> None: ...
if sys.version_info[:2] >= (3, 12):
def __buffer__(self, flags: int) -> memoryview: ...

Expand Down
25 changes: 16 additions & 9 deletions src/_backend_agg.h
Original file line number Diff line number Diff line change
Expand Up @@ -350,7 +350,8 @@ RendererAgg::_draw_path(path_t &path, bool has_clippath, const facepair_t &face,
agg::trans_affine hatch_trans;
hatch_trans *= agg::trans_affine_scaling(1.0, -1.0);
hatch_trans *= agg::trans_affine_translation(0.0, 1.0);
hatch_trans *= agg::trans_affine_scaling(hatch_size, hatch_size);
hatch_trans *= agg::trans_affine_scaling(static_cast<double>(hatch_size),
static_cast<double>(hatch_size));
hatch_path_trans_t hatch_path_trans(hatch_path, hatch_trans);
hatch_path_curve_t hatch_path_curve(hatch_path_trans);
hatch_path_stroke_t hatch_path_stroke(hatch_path_curve);
Expand Down Expand Up @@ -739,16 +740,19 @@ inline void RendererAgg::draw_text_image(GCAgg &gc, ImageArray &image, int x, in

set_clipbox(gc.cliprect, theRasterizer);

auto image_height = static_cast<double>(image.shape(0)),
image_width = static_cast<double>(image.shape(1));

agg::trans_affine mtx;
mtx *= agg::trans_affine_translation(0, -image.shape(0));
mtx *= agg::trans_affine_translation(0, -image_height);
mtx *= agg::trans_affine_rotation(-angle * (agg::pi / 180.0));
mtx *= agg::trans_affine_translation(x, y);

agg::path_storage rect;
rect.move_to(0, 0);
rect.line_to(image.shape(1), 0);
rect.line_to(image.shape(1), image.shape(0));
rect.line_to(0, image.shape(0));
rect.line_to(image_width, 0);
rect.line_to(image_width, image_height);
rect.line_to(0, image_height);
rect.line_to(0, 0);
agg::conv_transform<agg::path_storage> rect2(rect, mtx);

Expand Down Expand Up @@ -842,12 +846,15 @@ inline void RendererAgg::draw_image(GCAgg &gc,
agg::trans_affine mtx;
agg::path_storage rect;

mtx *= agg::trans_affine_translation((int)x, (int)(height - (y + image.shape(0))));
auto image_height = static_cast<double>(image.shape(0)),
image_width = static_cast<double>(image.shape(1));

mtx *= agg::trans_affine_translation((int)x, (int)(height - (y + image_height)));

rect.move_to(0, 0);
rect.line_to(image.shape(1), 0);
rect.line_to(image.shape(1), image.shape(0));
rect.line_to(0, image.shape(0));
rect.line_to(image_width, 0);
rect.line_to(image_width, image_height);
rect.line_to(0, image_height);
rect.line_to(0, 0);

agg::conv_transform<agg::path_storage> rect2(rect, mtx);
Expand Down
30 changes: 28 additions & 2 deletions src/_backend_agg_wrapper.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -58,11 +58,37 @@ PyRendererAgg_draw_path(RendererAgg *self,
static void
PyRendererAgg_draw_text_image(RendererAgg *self,
py::array_t<agg::int8u, py::array::c_style | py::array::forcecast> image_obj,
double x,
double y,
std::variant<double, int> vx,
std::variant<double, int> vy,
double angle,
GCAgg &gc)
{
int x, y;

if (auto value = std::get_if<double>(&vx)) {
auto api = py::module_::import("matplotlib._api");
auto warn = api.attr("warn_deprecated");
warn("since"_a="3.10", "name"_a="x", "obj_type"_a="parameter as float",
"alternative"_a="int(x)");
x = static_cast<int>(*value);
} else if (auto value = std::get_if<int>(&vx)) {
x = *value;
} else {
throw std::runtime_error("Should not happen");
}

if (auto value = std::get_if<double>(&vy)) {
auto api = py::module_::import("matplotlib._api");
auto warn = api.attr("warn_deprecated");
warn("since"_a="3.10", "name"_a="y", "obj_type"_a="parameter as float",
"alternative"_a="int(y)");
y = static_cast<int>(*value);
} else if (auto value = std::get_if<int>(&vy)) {
y = *value;
} else {
throw std::runtime_error("Should not happen");
}

// TODO: This really shouldn't be mutable, but Agg's renderer buffers aren't const.
auto image = image_obj.mutable_unchecked<2>();

Expand Down
3 changes: 2 additions & 1 deletion src/_image_resample.h
Original file line number Diff line number Diff line change
Expand Up @@ -566,7 +566,8 @@ class span_conv_alpha
{
if (m_alpha != 1.0) {
do {
span->a *= m_alpha;
span->a = static_cast<typename color_type::value_type>(
static_cast<typename color_type::calc_type>(span->a) * m_alpha);
++span;
} while (--len);
}
Expand Down
50 changes: 46 additions & 4 deletions src/ft2font_wrapper.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,30 @@
namespace py = pybind11;
using namespace pybind11::literals;

template <typename T>
using double_or_ = std::variant<double, T>;

template <typename T>
static T
_double_to_(const char *name, double_or_<T> &var)
{
if (auto value = std::get_if<double>(&var)) {
auto api = py::module_::import("matplotlib._api");
auto warn = api.attr("warn_deprecated");
warn("since"_a="3.10", "name"_a=name, "obj_type"_a="parameter as float",
"alternative"_a="int({})"_s.format(name));
return static_cast<T>(*value);
} else if (auto value = std::get_if<T>(&var)) {
return *value;
} else {
// pybind11 will have only allowed types that match the variant, so this `else`
// can't happen. We only have this case because older macOS doesn't support
// `std::get` and using the conditional `std::get_if` means an `else` to silence
// compiler warnings about "unhandled" cases.
throw std::runtime_error("Should not happen");
}
}

/**********************************************************************
* Enumerations
* */
Expand Down Expand Up @@ -227,8 +251,15 @@ const char *PyFT2Image_draw_rect_filled__doc__ = R"""(
)""";

static void
PyFT2Image_draw_rect_filled(FT2Image *self, double x0, double y0, double x1, double y1)
PyFT2Image_draw_rect_filled(FT2Image *self,
double_or_<long> vx0, double_or_<long> vy0,
double_or_<long> vx1, double_or_<long> vy1)
{
auto x0 = _double_to_<long>("x0", vx0);
auto y0 = _double_to_<long>("y0", vy0);
auto x1 = _double_to_<long>("x1", vx1);
auto y1 = _double_to_<long>("y1", vy1);

self->draw_rect_filled(x0, y0, x1, y1);
}

Expand Down Expand Up @@ -920,7 +951,7 @@ const char *PyFT2Font_draw_glyph_to_bitmap__doc__ = R"""(
----------
image : FT2Image
The image buffer on which to draw the glyph.
x, y : float
x, y : int
The pixel location at which to draw the glyph.
glyph : Glyph
The glyph to draw.
Expand All @@ -933,9 +964,13 @@ const char *PyFT2Font_draw_glyph_to_bitmap__doc__ = R"""(
)""";

static void
PyFT2Font_draw_glyph_to_bitmap(PyFT2Font *self, FT2Image &image, double xd, double yd,
PyFT2Font_draw_glyph_to_bitmap(PyFT2Font *self, FT2Image &image,
double_or_<int> vxd, double_or_<int> vyd,
PyGlyph *glyph, bool antialiased = true)
{
auto xd = _double_to_<int>("x", vxd);
auto yd = _double_to_<int>("y", vyd);

self->x->draw_glyph_to_bitmap(image, xd, yd, glyph->glyphInd, antialiased);
}

Expand Down Expand Up @@ -1625,7 +1660,14 @@ PYBIND11_MODULE(ft2font, m, py::mod_gil_not_used())

py::class_<FT2Image>(m, "FT2Image", py::is_final(), py::buffer_protocol(),
PyFT2Image__doc__)
.def(py::init<double, double>(), "width"_a, "height"_a, PyFT2Image_init__doc__)
.def(py::init(
[](double_or_<long> width, double_or_<long> height) {
return new FT2Image(
_double_to_<long>("width", width),
_double_to_<long>("height", height)
);
}),
"width"_a, "height"_a, PyFT2Image_init__doc__)
.def("draw_rect_filled", &PyFT2Image_draw_rect_filled,
"x0"_a, "y0"_a, "x1"_a, "y1"_a,
PyFT2Image_draw_rect_filled__doc__)
Expand Down
9 changes: 4 additions & 5 deletions src/tri/_tri.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -751,7 +751,7 @@ py::tuple TriContourGenerator::create_contour(const double& level)
Contour contour;

find_boundary_lines(contour, level);
find_interior_lines(contour, level, false, false);
find_interior_lines(contour, level, false);

return contour_line_to_segs_and_kinds(contour);
}
Expand All @@ -766,8 +766,8 @@ py::tuple TriContourGenerator::create_filled_contour(const double& lower_level,
Contour contour;

find_boundary_lines_filled(contour, lower_level, upper_level);
find_interior_lines(contour, lower_level, false, true);
find_interior_lines(contour, upper_level, true, true);
find_interior_lines(contour, lower_level, false);
find_interior_lines(contour, upper_level, true);

return contour_to_segs_and_kinds(contour);
}
Expand Down Expand Up @@ -880,8 +880,7 @@ void TriContourGenerator::find_boundary_lines_filled(Contour& contour,

void TriContourGenerator::find_interior_lines(Contour& contour,
const double& level,
bool on_upper,
bool filled)
bool on_upper)
{
const Triangulation& triang = _triangulation;
int ntri = triang.get_ntri();
Expand Down
6 changes: 2 additions & 4 deletions src/tri/_tri.h
Original file line number Diff line number Diff line change
Expand Up @@ -407,12 +407,10 @@ class TriContourGenerator final
* intersect any boundary.
* contour: Contour to add new lines to.
* level: Contour level.
* on_upper: Whether on upper or lower contour level.
* filled: Whether contours are filled or not. */
* on_upper: Whether on upper or lower contour level. */
void find_interior_lines(Contour& contour,
const double& level,
bool on_upper,
bool filled);
bool on_upper);

/* Follow contour line around boundary of the Triangulation from the
* specified TriEdge to its end which can be on either the lower or upper
Expand Down

0 comments on commit 3770dfe

Please sign in to comment.