Skip to content

Commit 2d7de1b

Browse files
committed
Add a pybind11 type caster for GCAgg and its requirements
1 parent 3a30cbc commit 2d7de1b

File tree

3 files changed

+120
-46
lines changed

3 files changed

+120
-46
lines changed

src/_backend_agg_wrapper.cpp

Lines changed: 9 additions & 44 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,17 +41,11 @@ 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
agg::rgba face)
4748
{
48-
GCAgg gc;
49-
50-
if (!convert_gcagg(gc_obj.ptr(), &gc)) {
51-
throw pybind11::error_already_set();
52-
}
53-
5449
self->draw_path(gc, path, trans, face);
5550
}
5651

@@ -60,52 +55,38 @@ PyRendererAgg_draw_text_image(RendererAgg *self,
6055
double x,
6156
double y,
6257
double angle,
63-
pybind11::object gc_obj)
58+
GCAgg &gc)
6459
{
6560
numpy::array_view<agg::int8u, 2> image;
66-
GCAgg gc;
6761

6862
if (!image.converter_contiguous(image_obj.ptr(), &image)) {
6963
throw pybind11::error_already_set();
7064
}
71-
if (!convert_gcagg(gc_obj.ptr(), &gc)) {
72-
throw pybind11::error_already_set();
73-
}
7465

7566
self->draw_text_image(gc, image, x, y, angle);
7667
}
7768

7869
static void
7970
PyRendererAgg_draw_markers(RendererAgg *self,
80-
pybind11::object gc_obj,
71+
GCAgg &gc,
8172
mpl::PathIterator marker_path,
8273
agg::trans_affine marker_path_trans,
8374
mpl::PathIterator path,
8475
agg::trans_affine trans,
8576
agg::rgba face)
8677
{
87-
GCAgg gc;
88-
89-
if (!convert_gcagg(gc_obj.ptr(), &gc)) {
90-
throw pybind11::error_already_set();
91-
}
92-
9378
self->draw_markers(gc, marker_path, marker_path_trans, path, trans, face);
9479
}
9580

9681
static void
9782
PyRendererAgg_draw_image(RendererAgg *self,
98-
pybind11::object gc_obj,
83+
GCAgg &gc,
9984
double x,
10085
double y,
10186
pybind11::array_t<agg::int8u, pybind11::array::c_style> image_obj)
10287
{
103-
GCAgg gc;
10488
numpy::array_view<agg::int8u, 3> image;
10589

106-
if (!convert_gcagg(gc_obj.ptr(), &gc)) {
107-
throw pybind11::error_already_set();
108-
}
10990
if (!image.set(image_obj.ptr())) {
11091
throw pybind11::error_already_set();
11192
}
@@ -119,7 +100,7 @@ PyRendererAgg_draw_image(RendererAgg *self,
119100

120101
static void
121102
PyRendererAgg_draw_path_collection(RendererAgg *self,
122-
pybind11::object gc_obj,
103+
GCAgg &gc,
123104
agg::trans_affine master_transform,
124105
pybind11::object paths_obj,
125106
pybind11::object transforms_obj,
@@ -128,25 +109,20 @@ PyRendererAgg_draw_path_collection(RendererAgg *self,
128109
pybind11::object facecolors_obj,
129110
pybind11::object edgecolors_obj,
130111
pybind11::object linewidths_obj,
131-
pybind11::object dashes_obj,
112+
DashesVector dashes,
132113
pybind11::object antialiaseds_obj,
133114
pybind11::object Py_UNUSED(ignored_obj),
134115
// offset position is no longer used
135116
pybind11::object Py_UNUSED(offset_position_obj))
136117
{
137-
GCAgg gc;
138118
mpl::PathGenerator paths;
139119
numpy::array_view<const double, 3> transforms;
140120
numpy::array_view<const double, 2> offsets;
141121
numpy::array_view<const double, 2> facecolors;
142122
numpy::array_view<const double, 2> edgecolors;
143123
numpy::array_view<const double, 1> linewidths;
144-
DashesVector dashes;
145124
numpy::array_view<const uint8_t, 1> antialiaseds;
146125

147-
if (!convert_gcagg(gc_obj.ptr(), &gc)) {
148-
throw pybind11::error_already_set();
149-
}
150126
if (!convert_pathgen(paths_obj.ptr(), &paths)) {
151127
throw pybind11::error_already_set();
152128
}
@@ -165,9 +141,6 @@ PyRendererAgg_draw_path_collection(RendererAgg *self,
165141
if (!linewidths.converter(linewidths_obj.ptr(), &linewidths)) {
166142
throw pybind11::error_already_set();
167143
}
168-
if (!convert_dashes_vector(dashes_obj.ptr(), &dashes)) {
169-
throw pybind11::error_already_set();
170-
}
171144
if (!antialiaseds.converter(antialiaseds_obj.ptr(), &antialiaseds)) {
172145
throw pybind11::error_already_set();
173146
}
@@ -187,7 +160,7 @@ PyRendererAgg_draw_path_collection(RendererAgg *self,
187160

188161
static void
189162
PyRendererAgg_draw_quad_mesh(RendererAgg *self,
190-
pybind11::object gc_obj,
163+
GCAgg &gc,
191164
agg::trans_affine master_transform,
192165
unsigned int mesh_width,
193166
unsigned int mesh_height,
@@ -198,15 +171,11 @@ PyRendererAgg_draw_quad_mesh(RendererAgg *self,
198171
bool antialiased,
199172
pybind11::object edgecolors_obj)
200173
{
201-
GCAgg gc;
202174
numpy::array_view<const double, 3> coordinates;
203175
numpy::array_view<const double, 2> offsets;
204176
numpy::array_view<const double, 2> facecolors;
205177
numpy::array_view<const double, 2> edgecolors;
206178

207-
if (!convert_gcagg(gc_obj.ptr(), &gc)) {
208-
throw pybind11::error_already_set();
209-
}
210179
if (!coordinates.converter(coordinates_obj.ptr(), &coordinates)) {
211180
throw pybind11::error_already_set();
212181
}
@@ -234,18 +203,14 @@ PyRendererAgg_draw_quad_mesh(RendererAgg *self,
234203

235204
static void
236205
PyRendererAgg_draw_gouraud_triangles(RendererAgg *self,
237-
pybind11::object gc_obj,
206+
GCAgg &gc,
238207
pybind11::object points_obj,
239208
pybind11::object colors_obj,
240209
agg::trans_affine trans)
241210
{
242-
GCAgg gc;
243211
numpy::array_view<const double, 3> points;
244212
numpy::array_view<const double, 3> colors;
245213

246-
if (!convert_gcagg(gc_obj.ptr(), &gc)) {
247-
throw pybind11::error_already_set();
248-
}
249214
if (!points.converter(points_obj.ptr(), &points)) {
250215
throw pybind11::error_already_set();
251216
}

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: 111 additions & 0 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"));
@@ -161,6 +194,59 @@ 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+
template <> struct type_caster<ClipPath> {
198+
public:
199+
PYBIND11_TYPE_CASTER(ClipPath, const_name("ClipPath"));
200+
201+
bool load(handle src, bool) {
202+
if (src.is_none()) {
203+
return true;
204+
}
205+
206+
auto clippath_tuple = src.cast<std::tuple<pybind11::object, agg::trans_affine>>();
207+
208+
if (!convert_path(std::get<0>(clippath_tuple).ptr(), &value.path)) {
209+
throw pybind11::error_already_set();
210+
}
211+
value.trans = std::get<1>(clippath_tuple);
212+
213+
return true;
214+
}
215+
};
216+
217+
template <> struct type_caster<Dashes> {
218+
public:
219+
PYBIND11_TYPE_CASTER(Dashes, const_name("Dashes"));
220+
221+
bool load(handle src, bool) {
222+
auto dash_tuple = src.cast<std::tuple<double, pybind11::object>>();
223+
auto dash_offset = std::get<0>(dash_tuple);
224+
auto dashes_seq_or_none = std::get<1>(dash_tuple);
225+
226+
if (dashes_seq_or_none.is_none()) {
227+
return true;
228+
}
229+
230+
auto dashes_seq = dashes_seq_or_none.cast<pybind11::sequence>();
231+
232+
auto nentries = dashes_seq.size();
233+
// If the dashpattern has odd length, iterate through it twice (in
234+
// accordance with the pdf/ps/svg specs).
235+
auto dash_pattern_length = (nentries % 2) ? 2 * nentries : nentries;
236+
237+
for (pybind11::size_t i = 0; i < dash_pattern_length; i += 2) {
238+
auto length = dashes_seq[i % nentries].cast<double>();
239+
auto skip = dashes_seq[(i + 1) % nentries].cast<double>();
240+
241+
value.add_dash_pair(length, skip);
242+
}
243+
244+
value.set_dash_offset(dash_offset);
245+
246+
return true;
247+
}
248+
};
249+
164250
template <> struct type_caster<SketchParams> {
165251
public:
166252
PYBIND11_TYPE_CASTER(SketchParams, const_name("SketchParams"));
@@ -177,6 +263,31 @@ namespace PYBIND11_NAMESPACE { namespace detail {
177263
return true;
178264
}
179265
};
266+
267+
template <> struct type_caster<GCAgg> {
268+
public:
269+
PYBIND11_TYPE_CASTER(GCAgg, const_name("GCAgg"));
270+
271+
bool load(handle src, bool) {
272+
value.linewidth = src.attr("_linewidth").cast<double>();
273+
value.alpha = src.attr("_alpha").cast<double>();
274+
value.forced_alpha = src.attr("_forced_alpha").cast<bool>();
275+
value.color = src.attr("_rgb").cast<agg::rgba>();
276+
value.isaa = src.attr("_antialiased").cast<bool>();
277+
value.cap = src.attr("_capstyle").cast<agg::line_cap_e>();
278+
value.join = src.attr("_joinstyle").cast<agg::line_join_e>();
279+
value.dashes = src.attr("get_dashes")().cast<Dashes>();
280+
value.cliprect = src.attr("_cliprect").cast<agg::rect_d>();
281+
value.clippath = src.attr("get_clip_path")().cast<ClipPath>();
282+
value.snap_mode = src.attr("get_snap")().cast<e_snap_mode>();
283+
value.hatchpath = src.attr("get_hatch_path")().cast<mpl::PathIterator>();
284+
value.hatch_color = src.attr("get_hatch_color")().cast<agg::rgba>();
285+
value.hatch_linewidth = src.attr("get_hatch_linewidth")().cast<double>();
286+
value.sketch = src.attr("get_sketch_params")().cast<SketchParams>();
287+
288+
return true;
289+
}
290+
};
180291
#endif
181292
}} // namespace PYBIND11_NAMESPACE::detail
182293

0 commit comments

Comments
 (0)