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

Skip to content

Commit c002273

Browse files
committed
Add a pybind11 type caster for GCAgg and its requirements
1 parent 444a791 commit c002273

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"
@@ -41,18 +42,13 @@ PyBufferRegion_get_extents(BufferRegion *self)
4142

4243
static void
4344
PyRendererAgg_draw_path(RendererAgg *self,
44-
py::object gc_obj,
45+
GCAgg &gc,
4546
mpl::PathIterator path,
4647
agg::trans_affine trans,
4748
py::object face_obj)
4849
{
49-
GCAgg gc;
5050
agg::rgba face;
5151

52-
if (!convert_gcagg(gc_obj.ptr(), &gc)) {
53-
throw py::error_already_set();
54-
}
55-
5652
if (!convert_face(face_obj.ptr(), gc, &face)) {
5753
throw py::error_already_set();
5854
}
@@ -66,37 +62,28 @@ PyRendererAgg_draw_text_image(RendererAgg *self,
6662
double x,
6763
double y,
6864
double angle,
69-
py::object gc_obj)
65+
GCAgg &gc)
7066
{
7167
numpy::array_view<agg::int8u, 2> image;
72-
GCAgg gc;
7368

7469
if (!image.converter_contiguous(image_obj.ptr(), &image)) {
7570
throw py::error_already_set();
7671
}
77-
if (!convert_gcagg(gc_obj.ptr(), &gc)) {
78-
throw py::error_already_set();
79-
}
8072

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

8476
static void
8577
PyRendererAgg_draw_markers(RendererAgg *self,
86-
py::object gc_obj,
78+
GCAgg &gc,
8779
mpl::PathIterator marker_path,
8880
agg::trans_affine marker_path_trans,
8981
mpl::PathIterator path,
9082
agg::trans_affine trans,
9183
py::object face_obj)
9284
{
93-
GCAgg gc;
9485
agg::rgba face;
9586

96-
if (!convert_gcagg(gc_obj.ptr(), &gc)) {
97-
throw py::error_already_set();
98-
}
99-
10087
if (!convert_face(face_obj.ptr(), gc, &face)) {
10188
throw py::error_already_set();
10289
}
@@ -106,17 +93,13 @@ PyRendererAgg_draw_markers(RendererAgg *self,
10693

10794
static void
10895
PyRendererAgg_draw_image(RendererAgg *self,
109-
py::object gc_obj,
96+
GCAgg &gc,
11097
double x,
11198
double y,
11299
py::array_t<agg::int8u, py::array::c_style> image_obj)
113100
{
114-
GCAgg gc;
115101
numpy::array_view<agg::int8u, 3> image;
116102

117-
if (!convert_gcagg(gc_obj.ptr(), &gc)) {
118-
throw py::error_already_set();
119-
}
120103
if (!image.set(image_obj.ptr())) {
121104
throw py::error_already_set();
122105
}
@@ -130,7 +113,7 @@ PyRendererAgg_draw_image(RendererAgg *self,
130113

131114
static void
132115
PyRendererAgg_draw_path_collection(RendererAgg *self,
133-
py::object gc_obj,
116+
GCAgg &gc,
134117
agg::trans_affine master_transform,
135118
py::object paths_obj,
136119
py::object transforms_obj,
@@ -139,25 +122,20 @@ PyRendererAgg_draw_path_collection(RendererAgg *self,
139122
py::object facecolors_obj,
140123
py::object edgecolors_obj,
141124
py::object linewidths_obj,
142-
py::object dashes_obj,
125+
DashesVector dashes,
143126
py::object antialiaseds_obj,
144127
py::object Py_UNUSED(ignored_obj),
145128
// offset position is no longer used
146129
py::object Py_UNUSED(offset_position_obj))
147130
{
148-
GCAgg gc;
149131
mpl::PathGenerator paths;
150132
numpy::array_view<const double, 3> transforms;
151133
numpy::array_view<const double, 2> offsets;
152134
numpy::array_view<const double, 2> facecolors;
153135
numpy::array_view<const double, 2> edgecolors;
154136
numpy::array_view<const double, 1> linewidths;
155-
DashesVector dashes;
156137
numpy::array_view<const uint8_t, 1> antialiaseds;
157138

158-
if (!convert_gcagg(gc_obj.ptr(), &gc)) {
159-
throw py::error_already_set();
160-
}
161139
if (!convert_pathgen(paths_obj.ptr(), &paths)) {
162140
throw py::error_already_set();
163141
}
@@ -176,9 +154,6 @@ PyRendererAgg_draw_path_collection(RendererAgg *self,
176154
if (!linewidths.converter(linewidths_obj.ptr(), &linewidths)) {
177155
throw py::error_already_set();
178156
}
179-
if (!convert_dashes_vector(dashes_obj.ptr(), &dashes)) {
180-
throw py::error_already_set();
181-
}
182157
if (!antialiaseds.converter(antialiaseds_obj.ptr(), &antialiaseds)) {
183158
throw py::error_already_set();
184159
}
@@ -198,7 +173,7 @@ PyRendererAgg_draw_path_collection(RendererAgg *self,
198173

199174
static void
200175
PyRendererAgg_draw_quad_mesh(RendererAgg *self,
201-
py::object gc_obj,
176+
GCAgg &gc,
202177
agg::trans_affine master_transform,
203178
unsigned int mesh_width,
204179
unsigned int mesh_height,
@@ -209,15 +184,11 @@ PyRendererAgg_draw_quad_mesh(RendererAgg *self,
209184
bool antialiased,
210185
py::object edgecolors_obj)
211186
{
212-
GCAgg gc;
213187
numpy::array_view<const double, 3> coordinates;
214188
numpy::array_view<const double, 2> offsets;
215189
numpy::array_view<const double, 2> facecolors;
216190
numpy::array_view<const double, 2> edgecolors;
217191

218-
if (!convert_gcagg(gc_obj.ptr(), &gc)) {
219-
throw py::error_already_set();
220-
}
221192
if (!coordinates.converter(coordinates_obj.ptr(), &coordinates)) {
222193
throw py::error_already_set();
223194
}
@@ -245,18 +216,14 @@ PyRendererAgg_draw_quad_mesh(RendererAgg *self,
245216

246217
static void
247218
PyRendererAgg_draw_gouraud_triangles(RendererAgg *self,
248-
py::object gc_obj,
219+
GCAgg &gc,
249220
py::object points_obj,
250221
py::object colors_obj,
251222
agg::trans_affine trans)
252223
{
253-
GCAgg gc;
254224
numpy::array_view<const double, 3> points;
255225
numpy::array_view<const double, 3> colors;
256226

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

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 <unordered_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::unordered_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::unordered_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<py::tuple>();
211+
212+
auto path = clippath_tuple[0];
213+
if (!path.is_none()) {
214+
value.path = path.cast<mpl::PathIterator>();
215+
}
216+
value.trans = clippath_tuple[1].cast<agg::trans_affine>();
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<py::tuple>();
228+
auto dash_offset = dash_tuple[0].cast<double>();
229+
auto dashes_seq_or_none = dash_tuple[1];
230+
231+
if (dashes_seq_or_none.is_none()) {
232+
return true;
233+
}
234+
235+
auto dashes_seq = dashes_seq_or_none.cast<py::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 (py::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"));
@@ -179,6 +270,32 @@ namespace PYBIND11_NAMESPACE { namespace detail {
179270
return true;
180271
}
181272
};
273+
274+
template <> struct type_caster<GCAgg> {
275+
public:
276+
PYBIND11_TYPE_CASTER(GCAgg, const_name("GCAgg"));
277+
278+
bool load(handle src, bool) {
279+
value.linewidth = src.attr("_linewidth").cast<double>();
280+
value.alpha = src.attr("_alpha").cast<double>();
281+
value.forced_alpha = src.attr("_forced_alpha").cast<bool>();
282+
value.color = src.attr("_rgb").cast<agg::rgba>();
283+
value.isaa = src.attr("_antialiased").cast<bool>();
284+
value.cap = src.attr("_capstyle").cast<agg::line_cap_e>();
285+
value.join = src.attr("_joinstyle").cast<agg::line_join_e>();
286+
value.dashes = src.attr("get_dashes")().cast<Dashes>();
287+
value.cliprect = src.attr("_cliprect").cast<agg::rect_d>();
288+
/* value.clippath = src.attr("get_clip_path")().cast<ClipPath>(); */
289+
convert_clippath(src.attr("get_clip_path")().ptr(), &value.clippath);
290+
value.snap_mode = src.attr("get_snap")().cast<e_snap_mode>();
291+
value.hatchpath = src.attr("get_hatch_path")().cast<mpl::PathIterator>();
292+
value.hatch_color = src.attr("get_hatch_color")().cast<agg::rgba>();
293+
value.hatch_linewidth = src.attr("get_hatch_linewidth")().cast<double>();
294+
value.sketch = src.attr("get_sketch_params")().cast<SketchParams>();
295+
296+
return true;
297+
}
298+
};
182299
#endif
183300
}} // namespace PYBIND11_NAMESPACE::detail
184301

0 commit comments

Comments
 (0)