88 * structures to C++ and Agg-friendly interfaces.
99 */
1010
11- #include < Python.h>
12-
13- #include " numpy/arrayobject.h"
11+ #include < pybind11/pybind11.h>
12+ #include < pybind11/numpy.h>
1413
1514#include " agg_basics.h"
16- #include " py_exceptions.h"
1715
18- extern " C" {
19- int convert_path (PyObject *obj, void *pathp);
20- }
16+ namespace py = pybind11;
2117
2218namespace mpl {
2319
@@ -35,8 +31,8 @@ class PathIterator
3531 underlying data arrays, so that Python reference counting
3632 can work.
3733 */
38- PyArrayObject * m_vertices;
39- PyArrayObject * m_codes;
34+ py:: array_t < double > m_vertices;
35+ py:: array_t < uint8_t > m_codes;
4036
4137 unsigned m_iterator;
4238 unsigned m_total_vertices;
@@ -50,38 +46,29 @@ class PathIterator
5046
5147 public:
5248 inline PathIterator ()
53- : m_vertices(NULL ),
54- m_codes(NULL ),
55- m_iterator(0 ),
49+ : m_iterator(0 ),
5650 m_total_vertices(0 ),
5751 m_should_simplify(false ),
5852 m_simplify_threshold(1.0 / 9.0 )
5953 {
6054 }
6155
62- inline PathIterator (PyObject *vertices,
63- PyObject *codes,
64- bool should_simplify,
56+ inline PathIterator (py::object vertices, py::object codes, bool should_simplify,
6557 double simplify_threshold)
66- : m_vertices( NULL ), m_codes( NULL ), m_iterator(0 )
58+ : m_iterator(0 )
6759 {
68- if (!set (vertices, codes, should_simplify, simplify_threshold))
69- throw mpl::exception ();
60+ set (vertices, codes, should_simplify, simplify_threshold);
7061 }
7162
72- inline PathIterator (PyObject * vertices, PyObject * codes)
73- : m_vertices( NULL ), m_codes( NULL ), m_iterator(0 )
63+ inline PathIterator (py::object vertices, py::object codes)
64+ : m_iterator(0 )
7465 {
75- if (!set (vertices, codes))
76- throw mpl::exception ();
66+ set (vertices, codes);
7767 }
7868
7969 inline PathIterator (const PathIterator &other)
8070 {
81- Py_XINCREF (other.m_vertices );
8271 m_vertices = other.m_vertices ;
83-
84- Py_XINCREF (other.m_codes );
8572 m_codes = other.m_codes ;
8673
8774 m_iterator = 0 ;
@@ -91,47 +78,45 @@ class PathIterator
9178 m_simplify_threshold = other.m_simplify_threshold ;
9279 }
9380
94- ~PathIterator ()
95- {
96- Py_XDECREF (m_vertices);
97- Py_XDECREF (m_codes);
98- }
99-
100- inline int
101- set (PyObject *vertices, PyObject *codes, bool should_simplify, double simplify_threshold)
81+ inline void
82+ set (py::object vertices, py::object codes, bool should_simplify, double simplify_threshold)
10283 {
10384 m_should_simplify = should_simplify;
10485 m_simplify_threshold = simplify_threshold;
10586
106- Py_XDECREF (m_vertices);
107- m_vertices = (PyArrayObject *)PyArray_FromObject (vertices, NPY_DOUBLE, 2 , 2 );
108-
109- if (!m_vertices || PyArray_DIM (m_vertices, 1 ) != 2 ) {
110- PyErr_SetString (PyExc_ValueError, " Invalid vertices array" );
111- return 0 ;
87+ m_vertices = vertices.cast <py::array_t <double >>();
88+ if (m_vertices.ndim () != 2 || m_vertices.shape (1 ) != 2 ) {
89+ throw py::value_error (" Invalid vertices array" );
11290 }
91+ m_total_vertices = m_vertices.shape (0 );
11392
114- Py_XDECREF (m_codes);
115- m_codes = NULL ;
116-
117- if (codes != NULL && codes != Py_None) {
118- m_codes = (PyArrayObject *)PyArray_FromObject (codes, NPY_UINT8, 1 , 1 );
119-
120- if (!m_codes || PyArray_DIM (m_codes, 0 ) != PyArray_DIM (m_vertices, 0 )) {
121- PyErr_SetString (PyExc_ValueError, " Invalid codes array" );
122- return 0 ;
93+ m_codes.release ().dec_ref ();
94+ if (!codes.is_none ()) {
95+ m_codes = codes.cast <py::array_t <uint8_t >>();
96+ if (m_codes.ndim () != 1 || m_codes.shape (0 ) != m_total_vertices) {
97+ throw py::value_error (" Invalid codes array" );
12398 }
12499 }
125100
126- m_total_vertices = (unsigned )PyArray_DIM (m_vertices, 0 );
127101 m_iterator = 0 ;
102+ }
128103
104+ inline int
105+ set (PyObject *vertices, PyObject *codes, bool should_simplify, double simplify_threshold)
106+ {
107+ try {
108+ set (py::reinterpret_borrow<py::object>(vertices),
109+ py::reinterpret_borrow<py::object>(codes),
110+ should_simplify, simplify_threshold);
111+ } catch (const py::error_already_set &) {
112+ return 0 ;
113+ }
129114 return 1 ;
130115 }
131116
132- inline int set (PyObject * vertices, PyObject * codes)
117+ inline void set (py::object vertices, py::object codes)
133118 {
134- return set (vertices, codes, false , 0.0 );
119+ set (vertices, codes, false , 0.0 );
135120 }
136121
137122 inline unsigned vertex (double *x, double *y)
@@ -144,12 +129,11 @@ class PathIterator
144129
145130 const size_t idx = m_iterator++;
146131
147- char *pair = (char *)PyArray_GETPTR2 (m_vertices, idx, 0 );
148- *x = *(double *)pair;
149- *y = *(double *)(pair + PyArray_STRIDE (m_vertices, 1 ));
132+ *x = *m_vertices.data (idx, 0 );
133+ *y = *m_vertices.data (idx, 1 );
150134
151- if (m_codes != NULL ) {
152- return ( unsigned )(*( char *) PyArray_GETPTR1 ( m_codes, idx) );
135+ if (m_codes) {
136+ return * m_codes. data ( idx);
153137 } else {
154138 return idx == 0 ? agg::path_cmd_move_to : agg::path_cmd_line_to;
155139 }
@@ -177,42 +161,38 @@ class PathIterator
177161
178162 inline bool has_codes () const
179163 {
180- return m_codes != NULL ;
164+ return bool ( m_codes) ;
181165 }
182166
183167 inline void *get_id ()
184168 {
185- return (void *)m_vertices;
169+ return (void *)m_vertices. ptr () ;
186170 }
187171};
188172
189173class PathGenerator
190174{
191- PyObject * m_paths;
175+ py::sequence m_paths;
192176 Py_ssize_t m_npaths;
193177
194178 public:
195179 typedef PathIterator path_iterator;
196180
197- PathGenerator () : m_paths( NULL ), m_npaths(0 ) {}
181+ PathGenerator () : m_npaths(0 ) {}
198182
199- ~PathGenerator ( )
183+ void set (py::object obj )
200184 {
201- Py_XDECREF (m_paths);
185+ m_paths = obj.cast <py::sequence>();
186+ m_npaths = m_paths.size ();
202187 }
203188
204189 int set (PyObject *obj)
205190 {
206- if (!PySequence_Check (obj)) {
191+ try {
192+ set (py::reinterpret_borrow<py::object>(obj));
193+ } catch (const py::error_already_set &) {
207194 return 0 ;
208195 }
209-
210- Py_XDECREF (m_paths);
211- m_paths = obj;
212- Py_INCREF (m_paths);
213-
214- m_npaths = PySequence_Size (m_paths);
215-
216196 return 1 ;
217197 }
218198
@@ -229,20 +209,44 @@ class PathGenerator
229209 path_iterator operator ()(size_t i)
230210 {
231211 path_iterator path;
232- PyObject *item;
233212
234- item = PySequence_GetItem (m_paths, i % m_npaths);
235- if (item == NULL ) {
236- throw mpl::exception ();
237- }
238- if (!convert_path (item, &path)) {
239- Py_DECREF (item);
240- throw mpl::exception ();
241- }
242- Py_DECREF (item);
213+ auto item = m_paths[i % m_npaths];
214+ path = item.cast <path_iterator>();
243215 return path;
244216 }
245217};
246218}
247219
220+ namespace PYBIND11_NAMESPACE { namespace detail {
221+ template <> struct type_caster <mpl::PathIterator> {
222+ public:
223+ PYBIND11_TYPE_CASTER (mpl::PathIterator, const_name(" PathIterator" ));
224+
225+ bool load (handle src, bool ) {
226+ if (src.is_none ()) {
227+ return true ;
228+ }
229+
230+ py::object vertices = src.attr (" vertices" );
231+ py::object codes = src.attr (" codes" );
232+ auto should_simplify = src.attr (" should_simplify" ).cast <bool >();
233+ auto simplify_threshold = src.attr (" simplify_threshold" ).cast <double >();
234+
235+ value.set (vertices, codes, should_simplify, simplify_threshold);
236+
237+ return true ;
238+ }
239+ };
240+
241+ template <> struct type_caster <mpl::PathGenerator> {
242+ public:
243+ PYBIND11_TYPE_CASTER (mpl::PathGenerator, const_name(" PathGenerator" ));
244+
245+ bool load (handle src, bool ) {
246+ value.set (py::reinterpret_borrow<py::object>(src));
247+ return true ;
248+ }
249+ };
250+ }} // namespace PYBIND11_NAMESPACE::detail
251+
248252#endif
0 commit comments