+void check_svp(ArtSVP*svp)
+{
+ int t;
+ for(t=0;t<svp->n_segs;t++) {
+ ArtSVPSeg* seg = &svp->segs[t];
+ int p;
+ for(p=0;p<seg->n_points-1;p++) {
+ ArtPoint* p1 = &seg->points[p];
+ ArtPoint* p2 = &seg->points[p+1];
+ if(p1->y > p2->y) {
+ fprintf(stderr, "bad svp, y in seg %08x is non-increasing\n");
+ exit(0);
+ }
+ }
+ }
+}
+
+void write_svp_postscript(const char*filename, ArtSVP*svp)
+{
+ printf("writing %s\n", filename);
+ FILE*fi = fopen(filename, "wb");
+ int i, j;
+ double xmin=0,ymin=0,xmax=0,ymax=0;
+ fprintf(fi, "%% begin\n");
+ for (i = 0; i < svp->n_segs; i++) {
+ for (j = 0; j < svp->segs[i].n_points; j++) {
+ double x = svp->segs[i].points[j].x;
+ double y = svp->segs[i].points[j].y;
+ if(i==0 && j==0) {
+ xmin = xmax = x;
+ ymin = ymax = y;
+ } else {
+ if(x < xmin) xmin = x;
+ if(x > xmax) xmax = x;
+ if(y < ymin) ymin = y;
+ if(y > ymax) ymax = y;
+ }
+ }
+ }
+ if(xmax == xmin) xmax=xmin+1;
+ if(ymax == ymin) ymax=ymin+1;
+
+ for (i = 0; i < svp->n_segs; i++)
+ {
+ fprintf(fi, "%g setgray\n", svp->segs[i].dir ? 0.7 : 0);
+ for (j = 0; j < svp->segs[i].n_points; j++)
+ {
+ //fprintf(fi, "%g %g %s\n",
+ // 20 + 550*(svp->segs[i].points[j].x-xmin)/(xmax-xmin),
+ // 820 - 800*(svp->segs[i].points[j].y-ymin)/(ymax-ymin),
+ // j ? "lineto" : "moveto");
+ fprintf(fi, "%.32f %.32f %s\n",
+ svp->segs[i].points[j].x,
+ svp->segs[i].points[j].y,
+ j ? "lineto" : "moveto");
+ }
+ fprintf(fi, "stroke\n");
+ }
+
+ fprintf(fi, "showpage\n");
+ fclose(fi);
+}
+
+void write_vpath_postscript(const char*filename, ArtVpath*path)
+{
+ FILE*fi = fopen(filename, "wb");
+ int i, j;
+ double xmin=0,ymin=0,xmax=0,ymax=0;
+ fprintf(fi, "%% begin\n");
+ ArtVpath*p = path;
+ char first = 1;
+ while(p->code != ART_END) {
+ if(p->code == ART_MOVETO || p->code == ART_MOVETO_OPEN) {
+ if(!first)
+ fprintf(fi, "stroke\n");
+ first = 0;
+ fprintf(fi, "0.0 setgray\n");
+ fprintf(fi, "%.32f %.32f moveto\n", p->x, p->y);
+ } else {
+ fprintf(fi, "%.32f %.32f lineto\n", p->x, p->y);
+ }
+ p++;
+ }
+ if(!first)
+ fprintf(fi, "stroke\n");
+ fprintf(fi, "showpage\n");
+ fclose(fi);
+}
+
+void write_gfxline_postscript(const char*filename, gfxline_t*line)
+{
+ FILE*fi = fopen(filename, "wb");
+ int i, j;
+ fprintf(fi, "%% begin\n");
+ char first = 1;
+ while(line) {
+ if(line->type == gfx_moveTo) {
+ if(!first)
+ fprintf(fi, "stroke\n");
+ first = 0;
+ fprintf(fi, "0.0 setgray\n");
+ fprintf(fi, "%.32f %.32f moveto\n", line->x, line->y);
+ } else {
+ fprintf(fi, "%.32f %.32f lineto\n", line->x, line->y);
+ }
+ line = line->next;
+ }
+ if(!first)
+ fprintf(fi, "stroke\n");
+ fprintf(fi, "showpage\n");
+ fclose(fi);
+}
+
+static int vpath_len(ArtVpath*svp)
+{
+ int len = 0;
+ while(svp->code != ART_END) {
+ svp ++;
+ len ++;
+ }
+ return len;
+}
+
+int gfxline_len(gfxline_t*line)
+{
+ gfxline_t*i = line;
+ int len = 0;
+ while(i) {
+ len ++;
+ i = i->next;
+ }
+ return len;
+}
+
+static ArtVpath*pvpath= 0;
+static int cmppos(const void*_p1, const void*_p2)
+{
+ int*p1 = (int*)_p1;
+ int*p2 = (int*)_p2;
+ ArtVpath*v1 = &pvpath[*p1];
+ ArtVpath*v2 = &pvpath[*p2];
+ if(v1->y < v2->y)
+ return -1;
+ else if(v1->y > v2->y)
+ return 1;
+ else if(v1->x < v2->x)
+ return -2;
+ else if(v1->x > v2->x)
+ return 2;
+ else
+ return 0;
+}
+
+#define PERTURBATION 2e-3
+static void my_perturb(ArtVpath*vpath)
+{
+ int t;
+ int len = vpath_len(vpath);
+ int*pos = (int*)malloc(len*sizeof(int));
+ for(t=0;t<len;t++)
+ pos[t] = t;
+ pvpath = vpath;
+ qsort(pos, len, sizeof(int), cmppos);
+ t=0;
+ while(t<len) {
+ int t2=t+1;
+ while(t2<len && !cmppos(&pos[t],&pos[t2])) {
+ t2++;
+ }
+
+ double dx = (PERTURBATION * rand ()) / RAND_MAX - PERTURBATION * 0.5;
+ double dy = (PERTURBATION * rand ()) / RAND_MAX - PERTURBATION * 0.5;
+ int s;
+ for(s=t;s<t2;s++) {
+ vpath[pos[s]].x += dx;
+ vpath[pos[s]].y += dy;
+ }
+ t = t2;
+ }
+ free(pos);
+ pvpath = 0;
+}
+
+static ArtSVP* gfxfillToSVP(gfxline_t*line, int perturb)