@@ -71,93 +71,22 @@ def buffer_info(self):
71
71
return (self .__data , self .__size )
72
72
73
73
74
- # Mapping from Matplotlib Path codes to cairo path codes.
75
- _MPL_TO_CAIRO_PATH_TYPE = np .zeros (80 , dtype = int ) # CLOSEPOLY = 79.
76
- _MPL_TO_CAIRO_PATH_TYPE [Path .MOVETO ] = cairo .PATH_MOVE_TO
77
- _MPL_TO_CAIRO_PATH_TYPE [Path .LINETO ] = cairo .PATH_LINE_TO
78
- _MPL_TO_CAIRO_PATH_TYPE [Path .CURVE4 ] = cairo .PATH_CURVE_TO
79
- _MPL_TO_CAIRO_PATH_TYPE [Path .CLOSEPOLY ] = cairo .PATH_CLOSE_PATH
80
- # Sizes in cairo_path_data_t of each cairo path element.
81
- _CAIRO_PATH_TYPE_SIZES = np .zeros (4 , dtype = int )
82
- _CAIRO_PATH_TYPE_SIZES [cairo .PATH_MOVE_TO ] = 2
83
- _CAIRO_PATH_TYPE_SIZES [cairo .PATH_LINE_TO ] = 2
84
- _CAIRO_PATH_TYPE_SIZES [cairo .PATH_CURVE_TO ] = 4
85
- _CAIRO_PATH_TYPE_SIZES [cairo .PATH_CLOSE_PATH ] = 1
86
-
87
-
88
- def _append_paths_slow (ctx , paths , transforms , clip = None ):
89
- for path , transform in zip (paths , transforms ):
90
- for points , code in path .iter_segments (
91
- transform , remove_nans = True , clip = clip ):
92
- if code == Path .MOVETO :
93
- ctx .move_to (* points )
94
- elif code == Path .CLOSEPOLY :
95
- ctx .close_path ()
96
- elif code == Path .LINETO :
97
- ctx .line_to (* points )
98
- elif code == Path .CURVE3 :
99
- cur = np .asarray (ctx .get_current_point ())
100
- a = points [:2 ]
101
- b = points [- 2 :]
102
- ctx .curve_to (* (cur / 3 + a * 2 / 3 ), * (a * 2 / 3 + b / 3 ), * b )
103
- elif code == Path .CURVE4 :
104
- ctx .curve_to (* points )
105
-
106
-
107
- def _append_paths_fast (ctx , paths , transforms , clip = None ):
108
- # We directly convert to the internal representation used by cairo, for
109
- # which ABI compatibility is guaranteed. The layout for each item is
110
- # --CODE(4)-- -LENGTH(4)- ---------PAD(8)---------
111
- # ----------X(8)---------- ----------Y(8)----------
112
- # with the size in bytes in parentheses, and (X, Y) repeated as many times
113
- # as there are points for the current code.
114
- ffi = cairo .ffi
115
-
116
- # Convert curves to segment, so that 1. we don't have to handle
117
- # variable-sized CURVE-n codes, and 2. we don't have to implement degree
118
- # elevation for quadratic Beziers.
119
- cleaneds = [path .cleaned (transform , remove_nans = True , clip = clip )
120
- for path , transform in zip (paths , transforms )]
121
- vertices = np .concatenate ([cleaned .vertices for cleaned in cleaneds ])
122
- codes = np .concatenate ([cleaned .codes for cleaned in cleaneds ])
123
-
124
- # Remove unused vertices and convert to cairo codes. Note that unlike
125
- # cairo_close_path, we do not explicitly insert an extraneous MOVE_TO after
126
- # CLOSE_PATH, so our resulting buffer may be smaller.
127
- vertices = vertices [(codes != Path .STOP ) & (codes != Path .CLOSEPOLY )]
128
- codes = codes [codes != Path .STOP ]
129
- codes = _MPL_TO_CAIRO_PATH_TYPE [codes ]
130
-
131
- # Where are the headers of each cairo portions?
132
- cairo_type_sizes = _CAIRO_PATH_TYPE_SIZES [codes ]
133
- cairo_type_positions = np .insert (np .cumsum (cairo_type_sizes ), 0 , 0 )
134
- cairo_num_data = cairo_type_positions [- 1 ]
135
- cairo_type_positions = cairo_type_positions [:- 1 ]
136
-
137
- # Fill the buffer.
138
- buf = np .empty (cairo_num_data * 16 , np .uint8 )
139
- as_int = np .frombuffer (buf .data , np .int32 )
140
- as_int [::4 ][cairo_type_positions ] = codes
141
- as_int [1 ::4 ][cairo_type_positions ] = cairo_type_sizes
142
- as_float = np .frombuffer (buf .data , np .float64 )
143
- mask = np .ones_like (as_float , bool )
144
- mask [::2 ][cairo_type_positions ] = mask [1 ::2 ][cairo_type_positions ] = False
145
- as_float [mask ] = vertices .ravel ()
146
-
147
- # Construct the cairo_path_t, and pass it to the context.
148
- ptr = ffi .new ("cairo_path_t *" )
149
- ptr .status = cairo .STATUS_SUCCESS
150
- ptr .data = ffi .cast ("cairo_path_data_t *" , ffi .from_buffer (buf ))
151
- ptr .num_data = cairo_num_data
152
- cairo .cairo .cairo_append_path (ctx ._pointer , ptr )
153
-
154
-
155
- _append_paths = (_append_paths_fast if cairo .__name__ == "cairocffi"
156
- else _append_paths_slow )
157
-
158
-
159
74
def _append_path (ctx , path , transform , clip = None ):
160
- return _append_paths (ctx , [path ], [transform ], clip )
75
+ for points , code in path .iter_segments (
76
+ transform , remove_nans = True , clip = clip ):
77
+ if code == Path .MOVETO :
78
+ ctx .move_to (* points )
79
+ elif code == Path .CLOSEPOLY :
80
+ ctx .close_path ()
81
+ elif code == Path .LINETO :
82
+ ctx .line_to (* points )
83
+ elif code == Path .CURVE3 :
84
+ cur = np .asarray (ctx .get_current_point ())
85
+ a = points [:2 ]
86
+ b = points [- 2 :]
87
+ ctx .curve_to (* (cur / 3 + a * 2 / 3 ), * (a * 2 / 3 + b / 3 ), * b )
88
+ elif code == Path .CURVE4 :
89
+ ctx .curve_to (* points )
161
90
162
91
163
92
class RendererCairo (RendererBase ):
0 commit comments