@@ -87,22 +87,88 @@ agg::trans_affine py_to_agg_transformation_matrix(const Py::Object& obj) {
87
87
inline void get_next_vertex (const char * & vertex_i, const char * vertex_end,
88
88
double & x, double & y,
89
89
size_t next_vertex_stride,
90
- size_t next_axis_stride) {
90
+ size_t next_axis_stride,
91
+ const char * & code_i, size_t code_stride) {
91
92
if (vertex_i + next_axis_stride >= vertex_end)
92
93
throw Py::ValueError (" Error parsing path. Read past end of vertices" );
93
94
x = *(double *)vertex_i;
94
95
y = *(double *)(vertex_i + next_axis_stride);
95
96
vertex_i += next_vertex_stride;
97
+ code_i += code_stride;
96
98
}
97
99
98
- #define GET_NEXT_VERTEX (x, y ) get_next_vertex(vertex_i, vertex_end, x, y, next_vertex_stride, next_axis_stride)
100
+ #define GET_NEXT_VERTEX (x, y ) get_next_vertex(vertex_i, vertex_end, x, y, next_vertex_stride, next_axis_stride, code_i, code_stride )
99
101
100
102
Py::Object BufferRegion::to_string (const Py::Tuple &args) {
101
103
102
104
// owned=true to prevent memory leak
103
105
return Py::String (PyString_FromStringAndSize ((const char *)aggbuf.data ,aggbuf.height *aggbuf.stride ), true );
104
106
}
105
107
108
+ class PathIterator {
109
+ PyArrayObject* vertices;
110
+ PyArrayObject* codes;
111
+ size_t m_iterator;
112
+ size_t m_total_vertices;
113
+
114
+ public:
115
+ PathIterator (const Py::Object& path_obj) :
116
+ vertices (NULL ), codes(NULL ), m_iterator(0 ) {
117
+ Py::Object vertices_obj = path_obj.getAttr (" vertices" );
118
+ Py::Object codes_obj = path_obj.getAttr (" codes" );
119
+
120
+ vertices = (PyArrayObject*)PyArray_ContiguousFromObject
121
+ (vertices_obj.ptr (), PyArray_DOUBLE, 2 , 2 );
122
+ if (!vertices || vertices->nd != 2 || vertices->dimensions [1 ] != 2 )
123
+ throw Py::ValueError (" Invalid vertices array." );
124
+ codes = (PyArrayObject*)PyArray_ContiguousFromObject
125
+ (codes_obj.ptr (), PyArray_UINT8, 1 , 1 );
126
+ if (!codes)
127
+ throw Py::ValueError (" Invalid codes array." );
128
+
129
+ if (codes->dimensions [0 ] != vertices->dimensions [0 ])
130
+ throw Py::ValueError (" Vertices and codes array are not the same length." );
131
+
132
+ m_total_vertices = codes->dimensions [0 ];
133
+ }
134
+
135
+ ~PathIterator () {
136
+ Py_XDECREF (vertices);
137
+ Py_XDECREF (codes);
138
+ }
139
+
140
+ static const char code_map[];
141
+
142
+ inline unsigned vertex (unsigned idx, double * x, double * y) {
143
+ if (idx > m_total_vertices)
144
+ throw Py::RuntimeError (" Requested vertex past end" );
145
+ double * pv = (double *)(vertices->data + (idx * vertices->strides [0 ]));
146
+ *x = *pv++;
147
+ *y = *pv;
148
+ // MGDTODO: Range check
149
+ return code_map[(unsigned int )*(codes->data + (idx * codes->strides [0 ]))];
150
+ }
151
+
152
+ inline unsigned vertex (double * x, double * y) {
153
+ if (m_iterator >= m_total_vertices) return agg::path_cmd_stop;
154
+ return vertex (m_iterator++, x, y);
155
+ }
156
+
157
+ inline void rewind (unsigned path_id) {
158
+ m_iterator = path_id;
159
+ }
160
+
161
+ inline unsigned total_vertices () {
162
+ return m_total_vertices;
163
+ }
164
+ };
165
+
166
+ const char PathIterator::code_map[] = {0 ,
167
+ agg::path_cmd_move_to,
168
+ agg::path_cmd_line_to,
169
+ agg::path_cmd_curve3,
170
+ agg::path_cmd_curve4,
171
+ agg::path_cmd_end_poly | agg::path_flags_close};
106
172
107
173
GCAgg::GCAgg (const Py::Object &gc, double dpi, bool snapto) :
108
174
dpi(dpi), snapto(snapto), isaa(true ), linewidth(1.0 ), alpha(1.0 ),
@@ -634,7 +700,7 @@ RendererAgg::draw_markers(const Py::Tuple& args) {
634
700
if (num_vertices) {
635
701
for (size_t j=0 ; j<num_vertices; ++j)
636
702
GET_NEXT_VERTEX (x, y);
637
- if (code_i == IGNORE )
703
+ if (* code_i == STOP || *code_i == CLOSEPOLY )
638
704
continue ;
639
705
640
706
trans.transform (&x, &y);
@@ -863,9 +929,10 @@ PathAgg::PathAgg(const Py::Object& path_obj) : curvy(false) {
863
929
864
930
for (size_t i = 0 ; i < N; ++i) {
865
931
switch (*(unsigned char *)(code_i)) {
866
- case IGNORE :
932
+ case STOP :
867
933
GET_NEXT_VERTEX (x0, y0);
868
- _VERBOSE (" IGNORE" );
934
+ _VERBOSE (" STOP" );
935
+ // MGDTODO: If this isn't the end, we should raise an error
869
936
break ;
870
937
case MOVETO:
871
938
GET_NEXT_VERTEX (x0, y0);
@@ -894,10 +961,10 @@ PathAgg::PathAgg(const Py::Object& path_obj) : curvy(false) {
894
961
break ;
895
962
case CLOSEPOLY:
<
F438
/td>896
963
close_polygon ();
964
+ GET_NEXT_VERTEX (x0, y0);
897
965
_VERBOSE (" CLOSEPOLY" );
898
966
break ;
899
967
}
900
- code_i += code_stride;
901
968
}
902
969
} catch (...) {
903
970
Py_XDECREF (vertices);
@@ -911,7 +978,7 @@ PathAgg::PathAgg(const Py::Object& path_obj) : curvy(false) {
911
978
912
979
Py::Object
913
980
RendererAgg::draw_path (const Py::Tuple& args) {
914
- typedef agg::conv_transform<agg::path_storage > transformed_path_t ;
981
+ typedef agg::conv_transform<PathIterator > transformed_path_t ;
915
982
typedef agg::conv_curve<transformed_path_t > curve_t ;
916
983
typedef agg::conv_stroke<curve_t > stroke_t ;
917
984
typedef agg::conv_dash<curve_t > dash_t ;
@@ -928,9 +995,11 @@ RendererAgg::draw_path(const Py::Tuple& args) {
928
995
929
996
GCAgg gc = GCAgg (args[0 ], dpi);
930
997
Py::Object path_obj = args[1 ];
931
- if (!PathAgg::check (path_obj))
932
- throw Py::TypeError (" Native path object is not of correct type" );
933
- PathAgg* path = static_cast <PathAgg*>(path_obj.ptr ());
998
+ // if (!PathAgg::check(path_obj))
999
+ // throw Py::TypeError("Native path object is not of correct type");
1000
+ // PathAgg* path = static_cast<PathAgg*>(path_obj.ptr());
1001
+ PathIterator path (path_obj);
1002
+
934
1003
agg::trans_affine trans = py_to_agg_transformation_matrix (args[2 ]);
935
1004
facepair_t face = _get_rgba_face (args[3 ], gc.alpha );
936
1005
@@ -943,34 +1012,34 @@ RendererAgg::draw_path(const Py::Tuple& args) {
943
1012
bool has_clippath = (gc.clippath != NULL );
944
1013
945
1014
if (has_clippath && (gc.clippath != lastclippath || trans != lastclippath_transform)) {
946
- rendererBaseAlphaMask->clear (agg::gray8 (0 , 0 ));
947
- gc.clippath ->rewind (0 );
948
- transformed_path_t transformed_clippath (*(gc.clippath ), trans);
949
- theRasterizer->add_path (transformed_clippath);
950
- rendererAlphaMask->color (agg::gray8 (255 , 255 ));
951
- agg::render_scanlines (*theRasterizer, *scanlineAlphaMask, *rendererAlphaMask);
952
- lastclippath = gc.clippath ;
953
- lastclippath_transform = trans;
1015
+ // rendererBaseAlphaMask->clear(agg::gray8(0, 0));
1016
+ // gc.clippath->rewind(0);
1017
+ // transformed_path_t transformed_clippath(*(gc.clippath), trans);
1018
+ // theRasterizer->add_path(transformed_clippath);
1019
+ // rendererAlphaMask->color(agg::gray8(255, 255));
1020
+ // agg::render_scanlines(*theRasterizer, *scanlineAlphaMask, *rendererAlphaMask);
1021
+ // lastclippath = gc.clippath;
1022
+ // lastclippath_transform = trans;
954
1023
}
955
1024
956
1025
try {
957
1026
// If this is a straight horizontal or vertical line, quantize to nearest
958
1027
// pixels
959
- if (path-> total_vertices () == 2 ) {
960
- double x0, y0, x1, y1;
961
- path-> vertex (0 , &x0, &y0);
962
- trans.transform (&x0, &y0);
963
- path-> vertex (1 , &x1, &y1);
964
- trans.transform (&x1, &y1);
965
- if (((int )x0 == (int )x1) || ((int )y0 == (int )y1)) {
966
- new_path.move_to ((int )x0 + 0.5 , (int )y0 + 0.5 );
967
- new_path.line_to ((int )x1 + 0.5 , (int )y1 + 0.5 );
968
- tpath = new transformed_path_t (new_path, agg::trans_affine ());
969
- }
970
- }
1028
+ // if (path. total_vertices() == 2) {
1029
+ // double x0, y0, x1, y1;
1030
+ // path. vertex(0, &x0, &y0);
1031
+ // trans.transform(&x0, &y0);
1032
+ // path. vertex(1, &x1, &y1);
1033
+ // trans.transform(&x1, &y1);
1034
+ // if (((int)x0 == (int)x1) || ((int)y0 == (int)y1)) {
1035
+ // new_path.move_to((int)x0 + 0.5, (int)y0 + 0.5);
1036
+ // new_path.line_to((int)x1 + 0.5, (int)y1 + 0.5);
1037
+ // tpath = new transformed_path_t(new_path, agg::trans_affine());
1038
+ // }
1039
+ // }
971
1040
972
1041
if (!tpath) {
973
- tpath = new transformed_path_t (* path, trans);
1042
+ tpath = new transformed_path_t (path, trans);
974
1043
}
975
1044
976
1045
// Benchmarking shows that there is no noticable slowdown to always
0 commit comments