13
13
* and friends.
14
14
*/
15
15
16
- #include < Python.h>
16
+ #include < pybind11/pybind11.h>
17
+ #include < pybind11/numpy.h>
18
+
19
+ namespace py = pybind11;
20
+
21
+ #include < unordered_map>
22
+
23
+ #include " agg_basics.h"
24
+ #include " agg_color_rgba.h"
25
+ #include " agg_trans_affine.h"
26
+ #include " path_converters.h"
17
27
18
28
extern " C" {
19
29
typedef int (*converter)(PyObject *, void *);
@@ -25,4 +35,287 @@ int convert_bboxes(PyObject *pygc, void *bboxp);
25
35
int convert_colors (PyObject *pygc, void *colorsp);
26
36
}
27
37
38
+ inline auto convert_points (py::array_t <double > obj)
39
+ {
40
+ check_trailing_shape (obj, " points" , 2 );
41
+ return obj.unchecked <2 >();
42
+ }
43
+
44
+ inline auto convert_transforms (py::array_t <double > obj)
45
+ {
46
+ check_trailing_shape (obj, " transforms" , 3 , 3 );
47
+ return obj.unchecked <3 >();
48
+ }
49
+
50
+ inline auto convert_bboxes (py::array_t <double > obj)
51
+ {
52
+ check_trailing_shape (obj, " bbox array" , 2 , 2 );
53
+ return obj.unchecked <3 >();
54
+ }
55
+
56
+ inline auto convert_colors (py::array_t <double > obj)
57
+ {
58
+ check_trailing_shape (obj, " colors" , 4 );
59
+ return obj.unchecked <2 >();
60
+ }
61
+
62
+ namespace PYBIND11_NAMESPACE { namespace detail {
63
+ template <> struct type_caster <agg::rect_d> {
64
+ public:
65
+ PYBIND11_TYPE_CASTER (agg::rect_d, const_name(" rect_d" ));
66
+
67
+ bool load (handle src, bool ) {
68
+ if (src.is_none ()) {
69
+ value.x1 = 0.0 ;
70
+ value.y1 = 0.0 ;
71
+ value.x2 = 0.0 ;
72
+ value.y2 = 0.0 ;
73
+ return true ;
74
+ }
75
+
76
+ auto rect_arr = py::array_t <double >::ensure (src);
77
+
78
+ if (rect_arr.ndim () == 2 ) {
79
+ if (rect_arr.shape (0 ) != 2 || rect_arr.shape (1 ) != 2 ) {
80
+ throw py::value_error (" Invalid bounding box" );
81
+ }
82
+
83
+ value.x1 = *rect_arr.data (0 , 0 );
84
+ value.y1 = *rect_arr.data (0 , 1 );
85
+ value.x2 = *rect_arr.data (1 , 0 );
86
+ value.y2 = *rect_arr.data (1 , 1 );
87
+
88
+ } else if (rect_arr.ndim () == 1 ) {
89
+ if (rect_arr.shape (0 ) != 4 ) {
90
+ throw py::value_error (" Invalid bounding box" );
91
+ }
92
+
93
+ value.x1 = *rect_arr.data (0 );
94
+ value.y1 = *rect_arr.data (1 );
95
+ value.x2 = *rect_arr.data (2 );
96
+ value.y2 = *rect_arr.data (3 );
97
+
98
+ } else {
99
+ throw py::value_error (" Invalid bounding box" );
100
+ }
101
+
102
+ return true ;
103
+ }
104
+ };
105
+
106
+ template <> struct type_caster <agg::rgba> {
107
+ public:
108
+ PYBIND11_TYPE_CASTER (agg::rgba, const_name(" rgba" ));
109
+
110
+ bool load (handle src, bool ) {
111
+ if (src.is_none ()) {
112
+ value.r = 0.0 ;
113
+ value.g = 0.0 ;
114
+ value.b = 0.0 ;
115
+ value.a = 0.0 ;
116
+ } else {
117
+ auto rgbatuple = src.cast <py::tuple>();
118
+ value.r = rgbatuple[0 ].cast <double >();
119
+ value.g = rgbatuple[1 ].cast <double >();
120
+ value.b = rgbatuple[2
F987
span>].cast <double >();
121
+ switch (rgbatuple.size ()) {
122
+ case 4 :
123
+ value.a = rgbatuple[3 ].cast <double >();
124
+ break ;
125
+ case 3 :
126
+ value.a = 1.0 ;
127
+ break ;
128
+ default :
129
+ throw py::value_error (" RGBA value must be 3- or 4-tuple" );
130
+ }
131
+ }
132
+ return true ;
133
+ }
134
+ };
135
+
136
+ template <> struct type_caster <agg::trans_affine> {
137
+ public:
138
+ PYBIND11_TYPE_CASTER (agg::trans_affine, const_name(" trans_affine" ));
139
+
140
+ bool load (handle src, bool ) {
141
+ // If None assume identity transform so leave affine unchanged
142
+ if (src.is_none ()) {
143
+ return true ;
144
+ }
145
+
146
+ auto array = py::array_t <double , py::array::c_style>::ensure (src);
147
+ if (!array || array.ndim () != 2 ||
148
+ array.shape (0 ) != 3 || array.shape (1 ) != 3 ) {
149
+ throw std::invalid_argument (" Invalid affine transformation matrix" );
150
+ }
151
+
152
+ auto buffer = array.data ();
153
+ value.sx = buffer[0 ];
154
+ value.shx = buffer[1 ];
155
+ value.tx = buffer[2 ];
156
+ value.shy = buffer[3 ];
157
+ value.sy = buffer[4 ];
158
+ value.ty = buffer[5 ];
159
+
160
+ return true ;
161
+ }
162
+ };
163
+
164
+ template <> struct type_caster <e_snap_mode> {
165
+ public:
166
+ PYBIND11_TYPE_CASTER (e_snap_mode, const_name(" e_snap_mode" ));
167
+
168
+ bool load (handle src, bool ) {
169
+ if (src.is_none ()) {
170
+ value = SNAP_AUTO;
171
+ return true ;
172
+ }
173
+
174
+ value = src.cast <bool >() ? SNAP_TRUE : SNAP_FALSE;
175
+
176
+ return true ;
177
+ }
178
+ };
179
+
180
+ /* Remove all this macro magic after dropping NumPy usage and just include `py_adaptors.h`. */
181
+ #ifdef MPL_PY_ADAPTORS_H
182
+ template <> struct type_caster <agg::line_cap_e> {
183
+ public:
184
+ PYBIND11_TYPE_CASTER (agg::line_cap_e, const_name(" line_cap_e" ));
185
+
186
+ bool load (handle src, bool ) {
187
+ const std::unordered_map<std::string, agg::line_cap_e> enum_values = {
188
+ {" butt" , agg::butt_cap},
189
+ {" round" , agg::round_cap},
190
+ {" projecting" , agg::square_cap},
191
+ };
192
+ value = enum_values.at (src.cast <std::string>());
193
+ return true ;
194
+ }
195
+ };
196
+
197
+ template <> struct type_caster <agg::line_join_e> {
198
+ public:
199
+ PYBIND11_TYPE_CASTER (agg::line_join_e, const_name(" line_join_e" ));
200
+
201
+ bool load (handle src, bool ) {
202
+ const std::unordered_map<std::string, agg::line_join_e> enum_values = {
203
+ {" miter" , agg::miter_join_revert},
204
+ {" round" , agg::round_join},
205
+ {" bevel" , agg::bevel_join},
206
+ };
207
+ value = agg::miter_join_revert;
208
+ value = enum_values.at (src.cast <std::string>());
209
+ return true ;
210
+ }
211
+ };
28
212
#endif
213
+
214
+ /* Remove all this macro magic after dropping NumPy usage and just include `_backend_agg_basic_types.h`. */
215
+ #ifdef MPL_BACKEND_AGG_BASIC_TYPES_H
216
+ # ifndef MPL_PY_ADAPTORS_H
217
+ # error "py_adaptors.h must be included to get Agg type casters"
218
+ # endif
219
+
220
+ template <> struct type_caster <ClipPath> {
221
+ public:
222
+ PYBIND11_TYPE_CASTER (ClipPath, const_name(" ClipPath" ));
223
+
224
+ bool load (handle src, bool ) {
225
+ if (src.is_none ()) {
226
+ return true ;
227
+ }
228
+
229
+ auto clippath_tuple = src.cast <py::tuple>();
230
+
231
+ auto path = clippath_tuple[0 ];
232
+ if (!path.is_none ()) {
233
+ value.path = path.cast <mpl::PathIterator>();
234
+ }
235
+ value.trans = clippath_tuple[1 ].cast <agg::trans_affine>();
236
+
237
+ return true ;
238
+ }
239
+ };
240
+
241
+ template <> struct type_caster <Dashes> {
242
+ public:
243
+ PYBIND11_TYPE_CASTER (Dashes, const_name(" Dashes" ));
244
+
245
+ bool load (handle src, bool ) {
246
+ auto dash_tuple = src.cast <py::tuple>();
247
+ auto dash_offset = dash_tuple[0 ].cast <double >();
248
+ auto dashes_seq_or_none = dash_tuple[1 ];
249
+
250
+ if (dashes_seq_or_none.is_none ()) {
251
+ return true ;
252
+ }
253
+
254
+ auto dashes_seq = dashes_seq_or_none.cast <py::sequence>();
255
+
256
+ auto nentries = dashes_seq.size ();
257
+ // If the dashpattern has odd length, iterate through it twice (in
258
+ // accordance with the pdf/ps/svg specs).
259
+ auto dash_pattern_length = (nentries % 2 ) ? 2 * nentries : nentries;
260
+
261
+ for (py::size_t i = 0 ; i < dash_pattern_length; i += 2 ) {
262
+ auto length = dashes_seq[i % nentries].cast <double >();
263
+ auto skip = dashes_seq[(i + 1 ) % nentries].cast <double >();
264
+
265
+ value.add_dash_pair (length, skip);
266
+ }
267
+
268
+ value.set_dash_offset (dash_offset);
269
+
270
+ return true ;
271
+ }
272
+ };
273
+
274
+ template <> struct type_caster <SketchParams> {
275
+ public:
276
+ PYBIND11_TYPE_CASTER (SketchParams, const_name(" SketchParams" ));
277
+
278
+ bool load (handle src, bool ) {
279
+ if (src.is_none ()) {
280
+ value.scale = 0.0 ;
281
+ value.length = 0.0 ;
282
+ value.randomness = 0.0 ;
283
+ return true ;
284
+ }
285
+
286
+ auto params = src.cast <std::tuple<double , double , double >>();
287
+ std::tie (value.scale , value.length , value.randomness ) = params;
288
+
289
+ return true ;
290
+ }
291
+ };
292
+
293
+ template <> struct type_caster <GCAgg> {
294
+ public:
295
+ PYBIND11_TYPE_CASTER (GCAgg, const_name(" GCAgg" ));
296
+
297
+ bool load (handle src, bool ) {
298
+ value.linewidth = src.attr (" _linewidth" ).cast <double >();
299
+ value.alpha = src.attr (" _alpha" ).cast <double >();
300
+ value.forced_alpha = src.attr (" _forced_alpha" ).cast <bool >();
301
+ value.color = src.attr (" _rgb" ).cast <agg::rgba>();
302
+ value.isaa = src.attr (" _antialiased" ).cast <bool >();
303
+ value.cap = src.attr (" _capstyle" ).cast <agg::line_cap_e>();
304
+ value.join = src.attr (" _joinstyle" ).cast <agg::line_join_e>();
305
+ value.dashes = src.attr (" get_dashes" )().cast <Dashes>();
306
+ value.cliprect = src.attr (" _cliprect" ).cast <agg::rect_d>();
307
+ /* value.clippath = src.attr("get_clip_path")().cast<ClipPath>(); */
308
+ convert_clippath (src.attr (" get_clip_path" )().ptr (), &value.clippath );
309
+ value.snap_mode = src.attr (" get_snap" )().cast <e_snap_mode>();
310
+ value.hatchpath = src.attr (" get_hatch_path" )().cast <mpl::PathIterator>();
311
+ value.hatch_color = src.attr (" get_hatch_color" )().cast <agg::rgba>();
312
+ value.hatch_linewidth = src.attr (" get_hatch_linewidth" )().cast <double >();
313
+ value.sketch = src.attr (" get_sketch_params" )().cast <SketchParams>();
314
+
315
+ return true ;
316
+ }
317
+ };
318
+ #endif
319
+ }} // namespace PYBIND11_NAMESPACE::detail
320
+
321
+ #endif /* MPL_PY_CONVERTERS_H */
0 commit comments