@@ -939,79 +939,151 @@ void cleanup_path(PathIterator &path,
939939 }
940940}
941941
942+ void quad2cubic (double x0, double y0,
943+ double x1, double y1,
944+ double x2, double y2,
945+ double *outx, double *outy)
946+ {
947+
948+ outx[0 ] = x0 + 2 ./3 . * (x1 - x0);
949+ outy[0 ] = y0 + 2 ./3 . * (y1 - y0);
950+ outx[1 ] = outx[0 ] + 1 ./3 . * (x2 - x0);
951+ outy[1 ] = outy[0 ] + 1 ./3 . * (y2 - y0);
952+ outx[2 ] = x2;
953+ outy[2 ] = y2;
954+ }
955+
956+ char *__append_to_string (char *p, char *buffer, size_t buffersize,
957+ const char *content)
958+ {
959+ for (const char *i = content; *i; ++i) {
960+ if (p < buffer || p - buffer >= (int )buffersize) {
961+ return p;
962+ }
963+
964+ *p++ = *i;
965+ }
966+
967+ return p;
968+ }
969+
942970template <class PathIterator >
943- void convert_to_svg (PathIterator &path,
944- agg::trans_affine &trans,
945- agg::rect_d &clip_rect,
946- bool simplify,
947- int precision,
948- char *buffer,
949- size_t *buffersize)
971+ void __convert_to_string (PathIterator &path,
972+ int precision,
973+ char **codes,
974+ bool postfix,
975+ char *buffer,
976+ size_t *buffersize)
950977{
951978#if PY_VERSION_HEX < 0x02070000
952979 char format[64 ];
953980 snprintf (format, 64 , " %s.%dg" , " %" , precision);
954981#endif
955982
956- typedef agg::conv_transform<py::PathIterator> transformed_path_t ;
957- typedef PathNanRemover<transformed_path_t > nan_removal_t ;
958- typedef PathClipper<nan_removal_t > clipped_t ;
959- typedef PathSimplifier<clipped_t > simplify_t ;
960-
961- bool do_clip = (clip_rect.x1 < clip_rect.x2 && clip_rect.y1 < clip_rect.y2 );
962-
963- transformed_path_t tpath (path, trans);
964- nan_removal_t nan_removed (tpath, true , path.has_curves ());
965- clipped_t clipped (nan_removed, do_clip, clip_rect);
966- simplify_t simplified (clipped, simplify, path.simplify_threshold ());
967-
968983 char *p = buffer;
984+ double x[3 ];
985+ double y[3 ];
986+ double last_x = 0.0 ;
987+ double last_y = 0.0 ;
969988
970- const char codes[] = { ' M' , ' L' , ' Q' , ' C' };
971- const int waits[] = { 1 , 1 , 2 , 3 };
972-
973- int wait = 0 ;
989+ const int sizes[] = { 1 , 1 , 2 , 3 };
990+ int size = 0 ;
974991 unsigned code;
975- double x = 0 , y = 0 ;
976- while ((code = simplified.vertex (&x, &y)) != agg::path_cmd_stop) {
977- if (wait == 0 ) {
978- *p++ = ' \n ' ;
979992
980- if (code == 0x4f ) {
981- *p++ = ' z' ;
982- *p++ = ' \n ' ;
983- continue ;
993+ while ((code = path.vertex (&x[0 ], &y[0 ])) != agg::path_cmd_stop) {
994+ if (code == 0x4f ) {
995+ p = __append_to_string (p, buffer, *buffersize, codes[4 ]);
996+ } else {
997+ size = sizes[code - 1 ];
998+
999+ for (int i = 1 ; i < size; ++i) {
1000+ path.vertex (&x[i], &y[i]);
9841001 }
9851002
986- *p++ = codes[code - 1 ];
987- wait = waits[code - 1 ];
988- } else {
989- *p++ = ' ' ;
990- }
1003+ /* For formats that don't support quad curves, convert to
1004+ cubic curves */
1005+ if (codes[code - 1 ][0 ] == ' \0 ' ) {
1006+ quad2cubic (last_x, last_y, x[0 ], y[0 ], x[1 ], y[1 ], x, y);
1007+ code++;
1008+ size = 3 ;
1009+ }
1010+
1011+ if (!postfix) {
1012+ p = __append_to_string (p, buffer, *buffersize, codes[code - 1 ]);
1013+ p = __append_to_string (p, buffer, *buffersize, " " );
1014+ }
9911015
1016+ for (int i = 0 ; i < size; ++i) {
9921017#if PY_VERSION_HEX >= 0x02070000
993- char *str;
994- str = PyOS_double_to_string (x, ' g' , precision, 0 , NULL );
995- p += snprintf (p, *buffersize - (p - buffer), " %s" , str);
996- PyMem_Free (str);
997- *p++ = ' ' ;
998- str = PyOS_double_to_string (y, ' g' , precision, 0 , NULL );
999- p += snprintf (p, *buffersize - (p - buffer), " %s" , str);
1000- PyMem_Free (str);
1018+ char *str;
1019+ str = PyOS_double_to_string (x[i], ' g' , precision, 0 , NULL );
1020+ p = __append_to_string (p, buffer, *buffersize, str);
1021+ PyMem_Free (str);
1022+ p = __append_to_string (p, buffer, *buffersize, " " );
1023+ str = PyOS_double_to_string (y[i], ' g' , precision, 0 , NULL );
1024+ p = __append_to_string (p, buffer, *buffersize, str);
1025+ PyMem_Free (str);
1026+ p = __append_to_string (p, buffer, *buffersize, " " );
10011027#else
1002- char str[64 ];
1003- PyOS_ascii_formatd (str, 64 , format, x);
1004- p += snprintf (p, *buffersize - (p - buffer), " %s" , str);
1005- *p++ = ' ' ;
1006- PyOS_ascii_formatd (str, 64 , format, y);
1007- p += snprintf (p, *buffersize - (p - buffer), " %s" , str);
1028+ char str[64 ];
1029+ PyOS_ascii_formatd (str, 64 , format, x[i]);
1030+ p = __append_to_string (p, buffer, *buffersize, str);
1031+ p = __append_to_string (p, buffer, *buffersize, " " );
1032+ PyOS_ascii_formatd (str, 64 , format, y[i]);
1033+ p = __append_to_string (p, buffer, *buffersize, str);
1034+ p = __append_to_string (p, buffer, *buffersize, " " );
10081035#endif
1036+ }
1037+
1038+ if (postfix) {
1039+ p = __append_to_string (p, buffer, *buffersize, codes[code - 1 ]);
1040+ }
1041+
1042+ last_x = x[size - 1 ];
1043+ last_y = y[size - 1 ];
1044+ }
10091045
1010- --wait ;
1046+ p = __append_to_string (p, buffer, *buffersize, " \n " ) ;
10111047 }
10121048
10131049 *p = ' \0 ' ;
10141050 *buffersize = p - buffer;
10151051}
10161052
1053+ template <class PathIterator >
1054+ void convert_to_string (PathIterator &path,
1055+ agg::trans_affine &trans,
1056+ agg::rect_d &clip_rect,
1057+ bool simplify,
1058+ SketchParams sketch_params,
1059+ int precision,
1060+ char **codes,
1061+ bool postfix,
1062+ char *buffer,
1063+ size_t *buffersize)
1064+ {
1065+ typedef agg::conv_transform<py::PathIterator> transformed_path_t ;
1066+ typedef PathNanRemover<transformed_path_t > nan_removal_t ;
1067+ typedef PathClipper<nan_removal_t > clipped_t ;
1068+ typedef PathSimplifier<clipped_t > simplify_t ;
1069+ typedef agg::conv_curve<simplify_t > curve_t ;
1070+ typedef Sketch<curve_t > sketch_t ;
1071+
1072+ bool do_clip = (clip_rect.x1 < clip_rect.x2 && clip_rect.y1 < clip_rect.y2 );
1073+
1074+ transformed_path_t tpath (path, trans);
1075+ nan_removal_t nan_removed (tpath, true , path.has_curves ());
1076+ clipped_t clipped (nan_removed, do_clip, clip_rect);
1077+ simplify_t simplified (clipped, simplify, path.simplify_threshold ());
1078+
1079+ if (sketch_params.scale == 0.0 ) {
1080+ __convert_to_string (simplified, precision, codes, postfix, buffer, buffersize);
1081+ } else {
1082+ curve_t curve (simplified);
1083+ sketch_t sketch (curve, sketch_params.scale , sketch_params.length , sketch_params.randomness );
1084+ __convert_to_string (sketch, precision, codes, postfix, buffer, buffersize);
1085+ }
1086+
1087+ }
1088+
10171089#endif
0 commit comments