8000 Merge branch 'pybind11-finals' into freethread · matplotlib/matplotlib@78b80a5 · GitHub
[go: up one dir, main page]

Skip to content

Commit 78b80a5

Browse files
committed
Merge branch 'pybind11-finals' into freethread
2 parents bce7107 + 0688bb3 commit 78b80a5

File tree

9 files changed

+398
-424
lines changed

9 files changed

+398
-424
lines changed

src/_backend_agg_basic_types.h

Lines changed: 136 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,9 @@
44
/* Contains some simple types from the Agg backend that are also used
55
by other modules */
66

7+
#include <pybind11/pybind11.h>
8+
9+
#include <unordered_map>
710
#include <vector>
811

912
#include "agg_color_rgba.h"
@@ -13,6 +16,8 @@
1316

1417
#include "py_adaptors.h"
1518

19+
namespace py = pybind11;
20+
1621
struct ClipPath
1722
{
1823
mpl::PathIterator path;
@@ -121,4 +126,135 @@ class GCAgg
121126
GCAgg &operator=(const GCAgg &);
122127
};
123128

129+
namespace PYBIND11_NAMESPACE { namespace detail {
130+
template <> struct type_caster<agg::line_cap_e> {
131+
public:
132+
PYBIND11_TYPE_CASTER(agg::line_cap_e, const_name("line_cap_e"));
133+
134+
bool load(handle src, bool) {
135+
const std::unordered_map<std::string, agg::line_cap_e> enum_values = {
136+
{"butt", agg::butt_cap},
137+
{"round", agg::round_cap},
138+
{"projecting", agg::square_cap},
139+
};
140+
value = enum_values.at(src.cast<std::string>());
141+
return true;
142+
}
143+
};
144+
145+
template <> struct type_caster<agg::line_join_e> {
146+
public:
147+
PYBIND11_TYPE_CASTER(agg::line_join_e, const_name("line_join_e"));
148+
149+
bool load(handle src, bool) {
150+
const std::unordered_map<std::string, agg::line_join_e> enum_values = {
151+
{"miter", agg::miter_join_revert},
152+
{"round", agg::round_join},
153+
{"bevel", agg::bevel_join},
154+
};
155+
value = agg::miter_join_revert;
156+
value = enum_values.at(src.cast<std::string>());
157+
return true;
158+
}
159+
};
160+
161+
template <> struct type_caster<ClipPath> {
162+
public:
163+
PYBIND11_TYPE_CASTER(ClipPath, const_name("ClipPath"));
164+
165+
bool load(handle src, bool) {
166+
if (src.is_none()) {
167+
return true;
168+
}
169+
170+
auto clippath_tuple = src.cast<py::tuple>();
171+
172+
auto path = clippath_tuple[0];
173+
if (!path.is_none()) {
174+
value.path = path.cast<mpl::PathIterator>();
175+
}
176+
value.trans = clippath_tuple[1].cast<agg::trans_affine>();
177+
178+
return true;
179+
}
180+
};
181+
182+
template <> struct type_caster<Dashes> {
183+
public:
184+
PYBIND11_TYPE_CASTER(Dashes, const_name("Dashes"));
185+
186+
bool load(handle src, bool) {
187+
auto dash_tuple = src.cast<py::tuple>();
188+
auto dash_offset = dash_tuple[0].cast<double>();
189+
auto dashes_seq_or_none = dash_tuple[1];
190+
191+
if (dashes_seq_or_none.is_none()) {
192+
return true;
193+
}
194+
195+
auto dashes_seq = dashes_seq_or_none.cast<py::sequence>();
196+
197+
auto nentries = dashes_seq.size();
198+
// If the dashpattern has odd length, iterate through it twice (in
199+
// accordance with the pdf/ps/svg specs).
200+
auto dash_pattern_length = (nentries % 2) ? 2 * nentries : nentries;
201+
202+
for (py::size_t i = 0; i < dash_pattern_length; i += 2) {
203+
auto length = dashes_seq[i % nentries].cast<double>();
204+
auto skip = dashes_seq[(i + 1) % nentries].cast<double>();
205+
206+
value.add_dash_pair(length, skip);
207+
}
208+
209+
value.set_dash_offset(dash_offset);
210+
211+
return true;
212+
}
213+
};
214+
215+
template <> struct type_caster<SketchParams> {
216+
public:
217+
PYBIND11_TYPE_CASTER(SketchParams, const_name("SketchParams"));
218+
219+
bool load(handle src, bool) {
220+
if (src.is_none()) {
221+
value.scale = 0.0;
222+
value.length = 0.0;
223+
value.randomness = 0.0;
224+
return true;
225+
}
226+
227+
auto params = src.cast<std::tuple<double, double, double>>();
228+
std::tie(value.scale, value.length, value.randomness) = params;
229+
230+
return true;
231+
}
232+
};
233+
234+
template <> struct type_caster<GCAgg> {
235+
public:
236+
PYBIND11_TYPE_CASTER(GCAgg, const_name("GCAgg"));
237+
238+
bool load(handle src, bool) {
239+
value.linewidth = src.attr("_linewidth").cast<double>();
240+
value.alpha = src.attr("_alpha").cast<double>();
241+
value.< 10000 span class="pl-smi">forced_alpha = src.attr("_forced_alpha").cast<bool>();
242+
value.color = src.attr("_rgb").cast<agg::rgba>();
243+
value.isaa = src.attr("_antialiased").cast<bool>();
244+
value.cap = src.attr("_capstyle").cast<agg::line_cap_e>();
245+
value.join = src.attr("_joinstyle").cast<agg::line_join_e>();
246+
value.dashes = src.attr("get_dashes")().cast<Dashes>();
247+
value.cliprect = src.attr("_cliprect").cast<agg::rect_d>();
248+
value.clippath = src.attr("get_clip_path")().cast<ClipPath>();
249+
value.snap_mode = src.attr("get_snap")().cast<e_snap_mode>();
250+
value.hatchpath = src.attr("get_hatch_path")().cast<mpl::PathIterator>();
251+
value.hatch_color = src.attr("get_hatch_color")().cast<agg::rgba>();
252+
value.hatch_linewidth = src.attr("get_hatch_linewidth")().cast<double>();
253+
value.sketch = src.attr("get_sketch_params")().cast<SketchParams>();
254+
255+
return true;
256+
}
257+
};
258+
}} // namespace PYBIND11_NAMESPACE::detail
259+
124260
#endif

src/_backend_agg_wrapper.cpp

Lines changed: 19 additions & 52 deletions
Original file line numberDiff line numberDiff line change
@@ -111,48 +111,25 @@ static void
111111
PyRendererAgg_draw_path_collection(RendererAgg *self,
112112
GCAgg &gc,
113113
agg::trans_affine master_transform,
114-
py::object paths_obj,
115-
py::object transforms_obj,
116-
py::object offsets_obj,
114+
mpl::PathGenerator paths,
115+
py::array_t<double> transforms_obj,
116+
py::array_t<double> offsets_obj,
117117
agg::trans_affine offset_trans,
118-
py::object facecolors_obj,
119-
py::object edgecolors_obj,
120-
py::object linewidths_obj,
118+
py::array_t<double> facecolors_obj,
119+
py::array_t<double> edgecolors_obj,
120+
py::array_t<double> linewidths_obj,
121121
DashesVector dashes,
122-
py::object antialiaseds_obj,
122+
py::array_t<uint8_t> antialiaseds_obj,
123123
py::object Py_UNUSED(ignored_obj),
124124
// offset position is no longer used
125125
py::object Py_UNUSED(offset_position_obj))
126126
{
127-
mpl::PathGenerator paths;
128-
numpy::array_view<const double, 3> transforms;
129-
numpy::array_view<const double, 2> offsets;
130-
numpy::array_view<const double, 2> facecolors;
131-
numpy::array_view<const double, 2> edgecolors;
132-
numpy::array_view<const double, 1> linewidths;
133-
numpy::array_view<const uint8_t, 1> antialiaseds;
134-
135-
if (!convert_pathgen(paths_obj.ptr(), &paths)) {
136-
throw py::error_already_set();
137-
}
138-
if (!convert_transforms(transforms_obj.ptr(), &transforms)) {
139-
throw py::error_already_set();
140-
}
141-
if (!convert_points(offsets_obj.ptr(), &offsets)) {
142-
throw py::error_already_set();
143-
}
144-
if (!convert_colors(facecolors_obj.ptr(), &facecolors)) {
145-
throw py::error_already_set();
146-
}
147-
if (!convert_colors(edgecolors_obj.ptr(), &edgecolors)) {
148-
throw py::error_already_set();
149-
}
150-
if (!linewidths.converter(linewidths_obj.ptr(), &linewidths)) {
151-
throw py::error_already_set();
152-
}
153-
if (!antialiaseds.converter(antialiaseds_obj.ptr(), &antialiaseds)) {
154-
throw py::error_already_set();
155-
}
127+
auto transforms = convert_transforms(transforms_obj);
128+
auto offsets = convert_points(offsets_obj);
129+
auto facecolors = convert_colors(facecolors_obj);
130+
auto edgecolors = convert_colors(edgecolors_obj);
131+
auto linewidths = linewidths_obj.unchecked<1>();
132+
auto antialiaseds = antialiaseds_obj.unchecked<1>();
156133

157134
self->draw_path_collection(gc,
158135
master_transform,
@@ -174,26 +151,16 @@ PyRendererAgg_draw_quad_mesh(RendererAgg *self,
174151
unsigned int mesh_width,
175152
unsigned int mesh_height,
176153
py::array_t<double, py::array::c_style | py::array::forcecast> coordinates_obj,
177-
py::object offsets_obj,
154+
py::array_t<double> offsets_obj,
178155
agg::trans_affine offset_trans,
179-
py::object facecolors_obj,
156+
py::array_t<double> facecolors_obj,
180157
bool antialiased,
181-
py::object edgecolors_obj)
158+
py::array_t<double> edgecolors_obj)
182159
{
183-
numpy::array_view<const double, 2> offsets;
184-
numpy::array_view<const double, 2> facecolors;
185-
numpy::array_view<const double, 2> edgecolors;
186-
187160
auto coordinates = coordinates_obj.mutable_unchecked<3>();
188-
if (!convert_points(offsets_obj.ptr(), &offsets)) {
189-
throw py::error_already_set();
190-
}
191-
if (!convert_colors(facecolors_obj.ptr(), &facecolors)) {
192-
throw py::error_already_set();
193-
}
194-
if (!convert_colors(edgecolors_obj.ptr(), &edgecolors)) {
195-
throw py::error_already_set();
196-
}
161+
auto offsets = convert_points(offsets_obj);
162+
auto facecolors = convert_colors(facecolors_obj);
163+
auto edgecolors = convert_colors(edgecolors_obj);
197164

198165
self->draw_quad_mesh(gc,
199166
master_transform,

src/_path.h

Lines changed: 27 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -245,8 +245,7 @@ inline void points_in_path(PointArray &points,
245245
typedef agg::conv_curve<no_nans_t> curve_t;
246246
typedef agg::conv_contour<curve_t> contour_t;
247247

248-
size_t i;
249-
for (i = 0; i < safe_first_shape(points); ++i) {
248+
for (auto i = 0; i < safe_first_shape(points); ++i) {
250249
result[i] = false;
251250
}
252251

@@ -270,10 +269,11 @@ template <class PathIterator>
270269
inline bool point_in_path(
271270
double x, double y, const double r, PathIterator &path, agg::trans_affine &trans)
272271
{
273-
npy_intp shape[] = {1, 2};
274-
numpy::array_view<double, 2> points(shape);
275-
points(0, 0) = x;
276-
points(0, 1) = y;
272+
py::ssize_t shape[] = {1, 2};
273+
py::array_t<double> points_arr(shape);
274+
*points_arr.mutable_data(0, 0) = x;
275+
*points_arr.mutable_data(0, 1) = y;
276+
auto points = points_arr.mutable_unchecked<2>();
277277

278278
int result[1];
279279
result[0] = 0;
@@ -292,10 +292,11 @@ inline bool point_on_path(
292292
typedef agg::conv_curve<no_nans_t> curve_t;
293293
typedef agg::conv_stroke<curve_t> stroke_t;
294294

295-
npy_intp shape[] = {1, 2};
296-
numpy::array_view<double, 2> points(shape);
297-
points(0, 0) = x;
298-
points(0, 1) = y;
295+
py::ssize_t shape[] = {1, 2};
296+
py::array_t<double> points_arr(shape);
297+
*points_arr.mutable_data(0, 0) = x;
298+
*points_arr.mutable_data(0, 1) = y;
299+
auto points = points_arr.mutable_unchecked<2>();
299300

300301
int result[1];
301302
result[0] = 0;
@@ -382,20 +383,19 @@ void get_path_collection_extents(agg::trans_affine &master_transform,
382383
throw std::runtime_error("Offsets array must have shape (N, 2)");
383384
}
384385

385-
size_t Npaths = paths.size();
386-
size_t Noffsets = safe_first_shape(offsets);
387-
size_t N = std::max(Npaths, Noffsets);
388-
size_t Ntransforms = std::min(safe_first_shape(transforms), N);
389-
size_t i;
386+
auto Npaths = paths.size();
387+
auto Noffsets = safe_first_shape(offsets);
388+
auto N = std::max(Npaths, Noffsets);
389+
auto Ntransforms = std::min(safe_first_shape(transforms), N);
390390

391391
agg::trans_affine trans;
392392

393393
reset_limits(extent);
394394

395-
for (i = 0; i < N; ++i) {
395+
for (auto i = 0; i < N; ++i) {
396396
typename PathGenerator::path_iterator path(paths(i % Npaths));
397397
if (Ntransforms) {
398-
size_t ti = i % Ntransforms;
398+
py::ssize_t ti = i % Ntransforms;
399399
trans = agg::trans_affine(transforms(ti, 0, 0),
400400
transforms(ti, 1, 0),
401401
transforms(ti, 0, 1),
@@ -429,24 +429,23 @@ void point_in_path_collection(double x,
429429
bool filled,
430430
std::vector<int> &result)
431431
{
432-
size_t Npaths = paths.size();
432+
auto Npaths = paths.size();
433433

434434
if (Npaths == 0) {
435435
return;
436436
}
437437

438-
size_t Noffsets = safe_first_shape(offsets);
439-
size_t N = std::max(Npaths, Noffsets);
440-
size_t Ntransforms = std::min(safe_first_shape(transforms), N);
441-
size_t i;
438+
auto Noffsets = safe_first_shape(offsets);
439+
auto N = std::max(Npaths, Noffsets);
440+
auto Ntransforms = std::min(safe_first_shape(transforms), N);
442441

443442
agg::trans_affine trans;
444443

445-
for (i = 0; i < N; ++i) {
444+
for (auto i = 0; i < N; ++i) {
446445
typename PathGenerator::path_iterator path = paths(i % Npaths);
447446

448447
if (Ntransforms) {
449-
size_t ti = i % Ntransforms;
448+
auto ti = i % Ntransforms;
450449
trans = agg::trans_affine(transforms(ti, 0, 0),
451450
transforms(ti, 1, 0),
452451
transforms(ti, 0, 1),
@@ -1224, AD05 17 +1223,15 @@ bool convert_to_string(PathIterator &path,
12241223
}
12251224

12261225
template<class T>
1227-
bool is_sorted_and_has_non_nan(PyArrayObject *array)
1226+
bool is_sorted_and_has_non_nan(py::array_t<T> array)
12281227
{
1229-
char* ptr = PyArray_BYTES(array);
1230-
npy_intp size = PyArray_DIM(array, 0),
1231-
stride = PyArray_STRIDE(array, 0);
1228+
auto size = array.shape(0);
12321229
using limits = std::numeric_limits<T>;
12331230
T last = limits::has_infinity ? -limits::infinity() : limits::min();
12341231
bool found_non_nan = false;
12351232

1236-
for (npy_intp i = 0; i < size; ++i, ptr += stride) {
1237-
T current = *(T*)ptr;
1233+
for (auto i = 0; i < size; ++i) {
1234+
T current = *array.data(i);
12381235
// The following tests !isnan(current), but also works for integral
12391236
// types. (The isnan(IntegralType) overload is absent on MSVC.)
12401237
if (current == current) {

0 commit comments

Comments
 (0)
0