Skip to content

Commit 50377f7

Browse files
committed
Add a pybind11 type caster for GCAgg and its requirements
1 parent 6554996 commit 50377f7

File tree

3 files changed

+130
-48
lines changed

3 files changed

+130
-48
lines changed

src/_backend_agg_wrapper.cpp

Lines changed: 9 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
#include <pybind11/pybind11.h>
22
#include <pybind11/numpy.h>
3+
#include <pybind11/stl.h>
34
#include "mplutils.h"
45
#include "numpy_cpp.h"
56
#include "py_converters.h"
@@ -40,18 +41,13 @@ PyBufferRegion_get_extents(BufferRegion *self)
4041

4142
static void
4243
PyRendererAgg_draw_path(RendererAgg *self,
43-
pybind11::object gc_obj,
44+
GCAgg &gc,
4445
mpl::PathIterator path,
4546
agg::trans_affine trans,
4647
pybind11::object face_obj)
4748
{
48-
GCAgg gc;
4949
agg::rgba face;
5050

51-
if (!convert_gcagg(gc_obj.ptr(), &gc)) {
52-
throw pybind11::error_already_set();
53-
}
54-
5551
if (!convert_face(face_obj.ptr(), gc, &face)) {
5652
throw pybind11::error_already_set();
5753
}
@@ -65,37 +61,28 @@ PyRendererAgg_draw_text_image(RendererAgg *self,
6561
double x,
6662
double y,
6763
double angle,
68-
pybind11::object gc_obj)
64+
GCAgg &gc)
6965
{
7066
numpy::array_view<agg::int8u, 2> image;
71-
GCAgg gc;
7267

7368
if (!image.converter_contiguous(image_obj.ptr(), &image)) {
7469
throw pybind11::error_already_set();
7570
}
76-
if (!convert_gcagg(gc_obj.ptr(), &gc)) {
77-
throw pybind11::error_already_set();
78-
}
7971

8072
self->draw_text_image(gc, image, x, y, angle);
8173
}
8274

8375
static void
8476
PyRendererAgg_draw_markers(RendererAgg *self,
85-
pybind11::object gc_obj,
77+
GCAgg &gc,
8678
mpl::PathIterator marker_path,
8779
agg::trans_affine marker_path_trans,
8880
mpl::PathIterator path,
8981
agg::trans_affine trans,
9082
pybind11::object face_obj)
9183
{
92-
GCAgg gc;
9384
agg::rgba face;
9485

95-
if (!convert_gcagg(gc_obj.ptr(), &gc)) {
96-
throw pybind11::error_already_set();
97-
}
98-
9986
if (!convert_face(face_obj.ptr(), gc, &face)) {
10087
throw pybind11::error_already_set();
10188
}
@@ -105,17 +92,13 @@ PyRendererAgg_draw_markers(RendererAgg *self,
10592

10693
static void
10794
PyRendererAgg_draw_image(RendererAgg *self,
108-
pybind11::object gc_obj,
95+
GCAgg &gc,
10996
double x,
11097
double y,
11198
pybind11::array_t<agg::int8u, pybind11::array::c_style> image_obj)
11299
{
113-
GCAgg gc;
114100
numpy::array_view<agg::int8u, 3> image;
115101

116-
if (!convert_gcagg(gc_obj.ptr(), &gc)) {
117-
throw pybind11::error_already_set();
118-
}
119102
if (!image.set(image_obj.ptr())) {
120103
throw pybind11::error_already_set();
121104
}
@@ -129,7 +112,7 @@ PyRendererAgg_draw_image(RendererAgg *self,
129112

130113
static void
131114
PyRendererAgg_draw_path_collection(RendererAgg *self,
132-
pybind11::object gc_obj,
115+
GCAgg &gc,
133116
agg::trans_affine master_transform,
134117
pybind11::object paths_obj,
135118
pybind11::object transforms_obj,
@@ -138,25 +121,20 @@ PyRendererAgg_draw_path_collection(RendererAgg *self,
138121
pybind11::object facecolors_obj,
139122
pybind11::object edgecolors_obj,
140123
pybind11::object linewidths_obj,
141-
pybind11::object dashes_obj,
124+
DashesVector dashes,
142125
pybind11::object antialiaseds_obj,
143126
pybind11::object Py_UNUSED(ignored_obj),
144127
// offset position is no longer used
145128
pybind11::object Py_UNUSED(offset_position_obj))
146129
{
147-
GCAgg gc;
148130
mpl::PathGenerator paths;
149131
numpy::array_view<const double, 3> transforms;
150132
numpy::array_view<const double, 2> offsets;
151133
numpy::array_view<const double, 2> facecolors;
152134
numpy::array_view<const double, 2> edgecolors;
153135
numpy::array_view<const double, 1> linewidths;
154-
DashesVector dashes;
155136
numpy::array_view<const uint8_t, 1> antialiaseds;
156137

157-
if (!convert_gcagg(gc_obj.ptr(), &gc)) {
158-
throw pybind11::error_already_set();
159-
}
160138
if (!convert_pathgen(paths_obj.ptr(), &paths)) {
161139
throw pybind11::error_already_set();
162140
}
@@ -175,9 +153,6 @@ PyRendererAgg_draw_path_collection(RendererAgg *self,
175153
if (!linewidths.converter(linewidths_obj.ptr(), &linewidths)) {
176154
throw pybind11::error_already_set();
177155
}
178-
if (!convert_dashes_vector(dashes_obj.ptr(), &dashes)) {
179-
throw pybind11::error_already_set();
180-
}
181156
if (!antialiaseds.converter(antialiaseds_obj.ptr(), &antialiaseds)) {
182157
throw pybind11::error_already_set();
183158
}
@@ -197,7 +172,7 @@ PyRendererAgg_draw_path_collection(RendererAgg *self,
197172

198173
static void
199174
PyRendererAgg_draw_quad_mesh(RendererAgg *self,
200-
pybind11::object gc_obj,
175+
GCAgg &gc,
201176
agg::trans_affine master_transform,
202177
unsigned int mesh_width,
203178
unsigned int mesh_height,
@@ -208,15 +183,11 @@ PyRendererAgg_draw_quad_mesh(RendererAgg *self,
208183
bool antialiased,
209184
pybind11::object edgecolors_obj)
210185
{
211-
GCAgg gc;
212186
numpy::array_view<const double, 3> coordinates;
213187
numpy::array_view<const double, 2> offsets;
214188
numpy::array_view<const double, 2> facecolors;
215189
numpy::array_view<const double, 2> edgecolors;
216190

217-
if (!convert_gcagg(gc_obj.ptr(), &gc)) {
218-
throw pybind11::error_already_set();
219-
}
220191
if (!coordinates.converter(coordinates_obj.ptr(), &coordinates)) {
221192
throw pybind11::error_already_set();
222193
}
@@ -244,18 +215,14 @@ PyRendererAgg_draw_quad_mesh(RendererAgg *self,
244215

245216
static void
246217
PyRendererAgg_draw_gouraud_triangles(RendererAgg *self,
247-
pybind11::object gc_obj,
218+
GCAgg &gc,
248219
pybind11::object points_obj,
249220
pybind11::object colors_obj,
250221
agg::trans_affine trans)
251222
{
252-
GCAgg gc;
253223
numpy::array_view<const double, 3> points;
254224
numpy::array_view<const double, 3> colors;
255225

256-
if (!convert_gcagg(gc_obj.ptr(), &gc)) {
257-
throw pybind11::error_already_set();
258-
}
259226
if (!points.converter(points_obj.ptr(), &points)) {
260227
throw pybind11::error_already_set();
261228
}

src/py_converters.cpp

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -415,8 +415,6 @@ int convert_pathgen(PyObject *obj, void *pathgenp)
415415
int convert_clippath(PyObject *clippath_tuple, void *clippathp)
416416
{
417417
ClipPath *clippath = (ClipPath *)clippathp;
418-
mpl::PathIterator path;
419-
agg::trans_affine trans;
420418

421419
if (clippath_tuple != NULL && clippath_tuple != Py_None) {
422420
if (!PyArg_ParseTuple(clippath_tuple,

src/py_converters_11.h

Lines changed: 121 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,8 @@
88

99
namespace py = pybind11;
1010

11+
#include <map>
12+
1113
#include "agg_basics.h"
1214
#include "agg_color_rgba.h"
1315
#include "agg_trans_affine.h"
@@ -135,6 +137,37 @@ namespace PYBIND11_NAMESPACE { namespace detail {
135137

136138
/* Remove all this macro magic after dropping NumPy usage and just include `py_adaptors.h`. */
137139
#ifdef MPL_PY_ADAPTORS_H
140+
template <> struct type_caster<agg::line_cap_e> {
141+
public:
142+
PYBIND11_TYPE_CASTER(agg::line_cap_e, const_name("line_cap_e"));
143+
144+
bool load(handle src, bool) {
145+
const std::map<std::string, agg::line_cap_e> enum_values = {
146+
{"butt", agg::butt_cap},
147+
{"round", agg::round_cap},
148+
{"projecting", agg::square_cap},
149+
};
150+
value = enum_values.at(src.cast<std::string>());
151+
return true;
152+
}
153+
};
154+
155+
template <> struct type_caster<agg::line_join_e> {
156+
public:
157+
PYBIND11_TYPE_CASTER(agg::line_join_e, const_name("line_join_e"));
158+
159+
bool load(handle src, bool) {
160+
const std::map<std::string, agg::line_join_e> enum_values = {
161+
{"miter", agg::miter_join_revert},
162+
{"round", agg::round_join},
163+
{"bevel", agg::bevel_join},
164+
};
165+
value = agg::miter_join_revert;
166+
value = enum_values.at(src.cast<std::string>());
167+
return true;
168+
}
169+
};
170+
138171
template <> struct type_caster<mpl::PathIterator> {
139172
public:
140173
PYBIND11_TYPE_CASTER(mpl::PathIterator, const_name("PathIterator"));
@@ -144,14 +177,14 @@ namespace PYBIND11_NAMESPACE { namespace detail {
144177
return true;
145178
}
146179

147-
auto vertices = src.attr("vertices");
148-
auto codes = src.attr("codes");
180+
py::object vertices = src.attr("vertices");
181+
py::object codes = src.attr("codes");
149182
auto should_simplify = src.attr("should_simplify").cast<bool>();
150183
auto simplify_threshold = src.attr("simplify_threshold").cast<double>();
151184

152-
if (!value.set(vertices.ptr(), codes.ptr(),
185+
if (!value.set(vertices.inc_ref().ptr(), codes.inc_ref().ptr(),
153186
should_simplify, simplify_threshold)) {
154-
return false;
187+
throw py::error_already_set();
155188
}
156189

157190
return true;
@@ -161,6 +194,64 @@ namespace PYBIND11_NAMESPACE { namespace detail {
161194

162195
/* Remove all this macro magic after dropping NumPy usage and just include `_backend_agg_basic_types.h`. */
163196
#ifdef MPL_BACKEND_AGG_BASIC_TYPES_H
197+
# ifndef MPL_PY_ADAPTORS_H
198+
# error "py_adaptors.h must be included to get Agg type casters"
199+
# endif
200+
201+
template <> struct type_caster<ClipPath> {
202+
public:
203+
PYBIND11_TYPE_CASTER(ClipPath, const_name("ClipPath"));
204+
205+
bool load(handle src, bool) {
206+
if (src.is_none()) {
207+
return true;
208+
}
209+
210+
auto clippath_tuple = src.cast<std::tuple<pybind11::object, agg::trans_affine>>();
211+
212+
auto path = std::get<0>(clippath_tuple);
213+
if (!path.is_none()) {
214+
value.path = path.cast<mpl::PathIterator>();
215+
}
216+
value.trans = std::get<1>(clippath_tuple);
217+
218+
return true;
219+
}
220+
};
221+
222+
template <> struct type_caster<Dashes> {
223+
public:
224+
PYBIND11_TYPE_CASTER(Dashes, const_name("Dashes"));
225+
226+
bool load(handle src, bool) {
227+
auto dash_tuple = src.cast<std::tuple<double, pybind11::object>>();
228+
auto dash_offset = std::get<0>(dash_tuple);
229+
auto dashes_seq_or_none = std::get<1>(dash_tuple);
230+
231+
if (dashes_seq_or_none.is_none()) {
232+
return true;
233+
}
234+
235+
auto dashes_seq = dashes_seq_or_none.cast<pybind11::sequence>();
236+
237+
auto nentries = dashes_seq.size();
238+
// If the dashpattern has odd length, iterate through it twice (in
239+
// accordance with the pdf/ps/svg specs).
240+
auto dash_pattern_length = (nentries % 2) ? 2 * nentries : nentries;
241+
242+
for (pybind11::size_t i = 0; i < dash_pattern_length; i += 2) {
243+
auto length = dashes_seq[i % nentries].cast<double>();
244+
auto skip = dashes_seq[(i + 1) % nentries].cast<double>();
245+
246+
value.add_dash_pair(length, skip);
247+
}
248+
249+
value.set_dash_offset(dash_offset);
250+
251+
return true;
252+
}
253+
};
254+
164255
template <> struct type_caster<SketchParams> {
165256
public:
166257
PYBIND11_TYPE_CASTER(SketchParams, const_name("SketchParams"));
@@ -177,6 +268,32 @@ namespace PYBIND11_NAMESPACE { namespace detail {
177268
return true;
178269
}
179270
};
271+
272+
template <> struct type_caster<GCAgg> {
273+
public:
274+
PYBIND11_TYPE_CASTER(GCAgg, const_name("GCAgg"));
275+
276+
bool load(handle src, bool) {
277+
value.linewidth = src.attr("_linewidth").cast<double>();
278+
value.alpha = src.attr("_alpha").cast<double>();
279+
value.forced_alpha = src.attr("_forced_alpha").cast<bool>();
280+
value.color = src.attr("_rgb").cast<agg::rgba>();
281+
value.isaa = src.attr("_antialiased").cast<bool>();
282+
value.cap = src.attr("_capstyle").cast<agg::line_cap_e>();
283+
value.join = src.attr("_joinstyle").cast<agg::line_join_e>();
284+
value.dashes = src.attr("get_dashes")().cast<Dashes>();
285+
value.cliprect = src.attr("_cliprect").cast<agg::rect_d>();
286+
/* value.clippath = src.attr("get_clip_path")().cast<ClipPath>(); */
287+
convert_clippath(src.attr("get_clip_path")().ptr(), &value.clippath);
288+
value.snap_mode = src.attr("get_snap")().cast<e_snap_mode>();
289+
value.hatchpath = src.attr("get_hatch_path")().cast<mpl::PathIterator>();
290+
value.hatch_color = src.attr("get_hatch_color")().cast<agg::rgba>();
291+
value.hatch_linewidth = src.attr("get_hatch_linewidth")().cast<double>();
292+
value.sketch = src.attr("get_sketch_params")().cast<SketchParams>();
293+
294+
return true;
295+
}
296+
};
180297
#endif
181298
}} // namespace PYBIND11_NAMESPACE::detail
182299

0 commit comments

Comments
 (0)