@@ -15,7 +15,10 @@ class PathIterator
1515 PyArrayObject* m_codes;
1616 size_t m_iterator;
1717 size_t m_total_vertices;
18+ size_t m_ok;
1819 bool m_should_simplify;
20+ static const unsigned char num_extra_points_map[16 ];
21+ static const unsigned code_map[];
1922
2023public:
2124 PathIterator (const Py::Object& path_obj) :
@@ -41,6 +44,7 @@ class PathIterator
4144 throw Py::ValueError (" Invalid codes array." );
4245 if (PyArray_DIM (m_codes, 0 ) != PyArray_DIM (m_vertices, 0 ))
4346 throw Py::ValueError (" Codes array is wrong length" );
47+ m_ok = 0 ;
4448 }
4549
4650 m_should_simplify = should_simplify_obj.isTrue ();
@@ -53,8 +57,6 @@ class PathIterator
5357 Py_XDECREF (m_codes);
5458 }
5559
56- static const unsigned code_map[];
57-
5860private:
5961 inline void vertex (const unsigned idx, double * x, double * y)
6062 {
@@ -82,20 +84,86 @@ class PathIterator
8284 if (m_iterator >= m_total_vertices) return agg::path_cmd_stop;
8385 unsigned code = vertex_with_code (m_iterator++, x, y);
8486
85- if (MPL_notisfinite64 (*x) || MPL_notisfinite64 (*y))
86- {
87- do
87+ if (!m_codes) {
88+ // This is the fast path for when we know we have no curves
89+ if ( MPL_notisfinite64 (*x) || MPL_notisfinite64 (*y))
8890 {
89- if (m_iterator < m_total_vertices)
91+ do
92+ {
93+ if (m_iterator < m_total_vertices)
94+ {
95+ vertex (m_iterator++, x, y);
96+ }
97+ else
98+ {
99+ return agg::path_cmd_stop;
100+ }
101+ } while (MPL_notisfinite64 (*x) || MPL_notisfinite64 (*y));
102+ return agg::path_cmd_move_to;
103+ }
104+ }
105+ else
106+ {
107+ // This is the slow method for when there might be curves.
108+
109+ /* If m_ok is 0, we look ahead to see if the next curve
110+ segment has any NaNs. If it does, we skip the whole
111+ thing and return a move_to to the first point of the
112+ next curve segment. This move_to may include NaNs,
113+ which is ok, since in that case, it will always be
114+ followed by another non-NaN move_to before any other
115+ curves are actually drawn. If the current curve
116+ segment doesn't have NaNs, we set the m_ok counter to
117+ the number of points in the curve segment, which will
118+ skip this check for the next N points.
119+ */
120+ if (m_ok == 0 ) {
121+ if (code == agg::path_cmd_stop ||
122+ code == (agg::path_cmd_end_poly | agg::path_flags_close))
90123 {
91- vertex (m_iterator++, x, y) ;
124+ return code ;
92125 }
93- else
126+
127+ size_t num_extra_points = num_extra_points_map[code & 0xF ];
128+ bool has_nan = (MPL_notisfinite64 (*x) || MPL_notisfinite64 (*y));
129+ for (size_t i = 0 ; !has_nan && i < num_extra_points; ++i)
130+ {
131+ double x0, y0;
132+ vertex (m_iterator + i, &x0, &y0);
133+ has_nan = (MPL_notisfinite64 (x0) || MPL_notisfinite64 (y0));
134+ }
135+
136+ if (has_nan)
137+ {
138+ m_iterator += num_extra_points;
139+ if (m_iterator < m_total_vertices)
140+ {
141+ code = vertex_with_code (m_iterator, x, y);
142+ if (code == agg::path_cmd_stop ||
143+ code == (agg::path_cmd_end_poly | agg::path_flags_close))
144+ {
145+ return code;
146+ }
147+ else
148+ {
149+ return agg::path_cmd_move_to;
150+ }
151+ }
152+ else
153+ {
154+ return agg::path_cmd_stop;
155+ }
156+ }
157+ else /* !has_nan */
94158 {
95- return agg::path_cmd_stop;
159+ m_ok = num_extra_points;
160+ return code;
96161 }
97- } while (MPL_notisfinite64 (*x) || MPL_notisfinite64 (*y));
98- return agg::path_cmd_move_to;
162+ }
163+ else /* m_ok != 0 */
164+ {
165+ m_ok--;
166+ }
99167 }
100168
101169 return code;
@@ -127,6 +195,12 @@ const unsigned PathIterator::code_map[] =
127195 agg::path_cmd_end_poly | agg::path_flags_close
128196 };
129197
198+ const unsigned char PathIterator::num_extra_points_map[] =
199+ {0 , 0 , 0 , 1 ,
200+ 2 , 0 , 0 , 0 ,
201+ 0 , 0 , 0 , 0 ,
202+ 0 , 0 , 0 , 0 };
203+
130204#define DEBUG_SIMPLIFY 0
131205
132206template <class VertexSource >
0 commit comments