/* File: svgdraw.c * * This file is part of XSCHEM, * a schematic capture and Spice/Vhdl/Verilog netlisting tool for circuit * simulation. * Copyright (C) 1998-2020 Stefan Frederik Schippers * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #include "xschem.h" #define X_TO_SVG(x) ( (x+xorigin)* mooz ) #define Y_TO_SVG(y) ( (y+yorigin)* mooz ) static FILE *fd; typedef struct { int red; int green; int blue; } Svg_color; static Svg_color *svg_colors; static double svg_linew; /* current width of lines / rectangles */ static Svg_color svg_stroke; static void restore_lw(void) { svg_linew = lw_double*0.7; } static void set_svg_colors(unsigned int pixel) { if(color_ps) { svg_stroke.red = svg_colors[pixel].red; svg_stroke.green = svg_colors[pixel].green; svg_stroke.blue = svg_colors[pixel].blue; } else { if(dark_colorscheme == 0 ) { svg_stroke.red = 0; svg_stroke.green = 0; svg_stroke.blue = 0; } else { svg_stroke.red = 255; svg_stroke.green = 255; svg_stroke.blue = 255; } } } static void svg_xdrawline(int layer, double x1, double y1, double x2, double y2, int dash) { fprintf(fd,"\n", x1, y1, x2, y2); } static void svg_xdrawpoint(int layer, double x1, double y1) { fprintf(fd,"\n", x1, y1, x1+1.0, y1, x1+1.0, y1+1.0, x1, y1+1.0, x1, y1); } static void svg_xfillrectangle(int layer, double x1, double y1, double x2, double y2, int dash) { fprintf(fd,"\n", x1, y1, x2, y1, x2, y2, x1, y2, x1, y1); } static void svg_drawpolygon(int c, int what, double *x, double *y, int points, int fill, int dash) { double x1,y1,x2,y2; double xx, yy; int i; polygon_bbox(x, y, points, &x1,&y1,&x2,&y2); x1=X_TO_SVG(x1); y1=Y_TO_SVG(y1); x2=X_TO_SVG(x2); y2=Y_TO_SVG(y2); if( !rectclip(areax1,areay1,areax2,areay2,&x1,&y1,&x2,&y2) ) { return; } fprintf(fd, "\n"); */ fprintf(fd, "\"/>\n"); } static void svg_filledrect(int gc, double rectx1,double recty1,double rectx2,double recty2, int dash) { double x1,y1,x2,y2; x1=X_TO_SVG(rectx1); y1=Y_TO_SVG(recty1); x2=X_TO_SVG(rectx2); y2=Y_TO_SVG(recty2); if( rectclip(areax1,areay1,areax2,areay2,&x1,&y1,&x2,&y2) ) { svg_xfillrectangle(gc, x1,y1,x2,y2, dash); } } static void svg_drawcircle(int gc, int fillarc, double x,double y,double r,double a, double b) { double xx,yy,rr; double x1, y1, x2, y2; xx=X_TO_SVG(x); yy=Y_TO_SVG(y); rr=r*mooz; arc_bbox(x, y, r, a, b, &x1,&y1,&x2,&y2); x1=X_TO_SVG(x1); y1=Y_TO_SVG(y1); x2=X_TO_SVG(x2); y2=Y_TO_SVG(y2); if( rectclip(areax1,areay1,areax2,areay2,&x1,&y1,&x2,&y2) ) { fprintf(fd, "\n", xx, yy, rr, svg_stroke.red, svg_stroke.green, svg_stroke.blue, svg_stroke.red, svg_stroke.green, svg_stroke.blue, svg_linew/4); } } static void svg_drawarc(int gc, int fillarc, double x,double y,double r,double a, double b, int dash) { double xx,yy,rr; double x1, y1, x2, y2; double xx1, yy1, xx2, yy2; int fs, fa; xx=X_TO_SVG(x); yy=Y_TO_SVG(y); rr=r*mooz; arc_bbox(x, y, r, a, b, &x1,&y1,&x2,&y2); x1=X_TO_SVG(x1); y1=Y_TO_SVG(y1); x2=X_TO_SVG(x2); y2=Y_TO_SVG(y2); if( rectclip(areax1,areay1,areax2,areay2,&x1,&y1,&x2,&y2) ) { if(b == 360.) { fprintf(fd, "\n", svg_stroke.red, svg_stroke.green, svg_stroke.blue, svg_stroke.red, svg_stroke.green, svg_stroke.blue, svg_linew); else fprintf(fd, "stroke=\"rgb(%d,%d,%d)\" fill=\"none\" stroke-width=\"%g\"/>\n", svg_stroke.red, svg_stroke.green, svg_stroke.blue, svg_linew); } else { xx1 = rr * cos(a * XSCH_PI / 180.) + xx; yy1 = -rr * sin(a * XSCH_PI / 180.) + yy; xx2 = rr * cos((a + b) * XSCH_PI / 180.) + xx; yy2 = -rr * sin((a + b) * XSCH_PI / 180.) + yy; fa = b > 180 ? 1 : 0; fs = b > 0 ? 0 : 1; fprintf(fd,"\n", xx1, yy1, rr, rr, fa, fs, xx2, yy2); } } } static void svg_drawline(int gc, double linex1,double liney1,double linex2,double liney2, int dash) { double x1,y1,x2,y2; x1=X_TO_SVG(linex1); y1=Y_TO_SVG(liney1); x2=X_TO_SVG(linex2); y2=Y_TO_SVG(liney2); if( clip(&x1,&y1,&x2,&y2) ) { svg_xdrawline(gc, x1, y1, x2, y2, dash); } } static void svg_draw_string(int gctext, const char *str, int rot, int flip, int hcenter, int vcenter, double x1,double y1, double xscale, double yscale) { double a,yy,curr_x1,curr_y1,curr_x2,curr_y2,rx1,rx2,ry1,ry2; int pos=0,cc,pos2=0; int i; if(str==NULL) return; #ifdef HAS_CAIRO text_bbox_nocairo(str, xscale, yscale, rot, flip, hcenter, vcenter, x1,y1, &rx1,&ry1,&rx2,&ry2); #else text_bbox(str, xscale, yscale, rot, flip, hcenter, vcenter, x1,y1, &rx1,&ry1,&rx2,&ry2); #endif xscale*=nocairo_font_xscale; yscale*=nocairo_font_yscale; if(!textclip(areax1,areay1,areax2,areay2,rx1,ry1,rx2,ry2)) return; x1=rx1;y1=ry1; if(rot&1) {y1=ry2;rot=3;} else rot=0; flip = 0; yy=y1; while(str[pos2]) { cc = (int)str[pos2++]; if(cc=='\n') { yy+=(FONTHEIGHT+FONTDESCENT+FONTWHITESPACE)* yscale; pos=0; continue; } a = pos*(FONTWIDTH+FONTWHITESPACE); for(i=0;iareay1 && yareax1 && xlines[layer];j++) { line = ((inst_ptr[n].ptr+instdef)->lineptr[layer])[j]; ROTATION(0.0,0.0,line.x1,line.y1,x1,y1); ROTATION(0.0,0.0,line.x2,line.y2,x2,y2); ORDER(x1,y1,x2,y2); svg_drawline(layer, x0+x1, y0+y1, x0+x2, y0+y2, line.dash); } for(j=0;j< (inst_ptr[n].ptr+instdef)->polygons[layer];j++) /* 20171115 */ { polygon = ((inst_ptr[n].ptr+instdef)->polygonptr[layer])[j]; { /* scope block so we declare some auxiliary arrays for coord transforms. 20171115 */ int k; double *x = my_malloc(417, sizeof(double) * polygon.points); double *y = my_malloc(418, sizeof(double) * polygon.points); for(k=0;karcs[layer];j++) { double angle; arc = ((inst_ptr[n].ptr+instdef)->arcptr[layer])[j]; if(flip) { angle = 270.*rot+180.-arc.b-arc.a; } else { angle = arc.a+rot*270.; } angle = fmod(angle, 360.); if(angle<0.) angle+=360.; ROTATION(0.0,0.0,arc.x,arc.y,x1,y1); svg_drawarc(layer, arc.fill, x0+x1, y0+y1, arc.r, angle, arc.b, arc.dash); } if( (layer != PINLAYER || enable_layer[layer]) ) for(j=0;j< (inst_ptr[n].ptr+instdef)->rects[layer];j++) { box = ((inst_ptr[n].ptr+instdef)->boxptr[layer])[j]; ROTATION(0.0,0.0,box.x1,box.y1,x1,y1); ROTATION(0.0,0.0,box.x2,box.y2,x2,y2); RECTORDER(x1,y1,x2,y2); svg_filledrect(layer, x0+x1, y0+y1, x0+x2, y0+y2, box.dash); } if( (layer==TEXTWIRELAYER && !(inst_ptr[n].flags&2) ) || (sym_txt && (layer==TEXTLAYER) && (inst_ptr[n].flags&2) ) ) { const char *txtptr; for(j=0;j< (inst_ptr[n].ptr+instdef)->texts;j++) { text = (inst_ptr[n].ptr+instdef)->txtptr[j]; /* if(text.xscale*FONTWIDTH* mooz<1) continue; */ txtptr= translate(n, text.txt_ptr); ROTATION(0.0,0.0,text.x0,text.y0,x1,y1); textlayer = layer; if( !(layer == PINLAYER && (inst_ptr[n].flags & 4))) { textlayer = (inst_ptr[n].ptr+instdef)->txtptr[j].layer; if(textlayer < 0 || textlayer >= cadlayers) textlayer = layer; } if((layer == PINLAYER && inst_ptr[n].flags & 4) || enable_layer[textlayer]) { svg_draw_string(textlayer, txtptr, (text.rot + ( (flip && (text.rot & 1) ) ? rot+2 : rot) ) & 0x3, flip^text.flip, text.hcenter, text.vcenter, x0+x1, y0+y1, text.xscale, text.yscale); } } } Tcl_SetResult(interp,"",TCL_STATIC); /*26102003 */ } static void fill_svg_colors() { char s[200]; /* overflow safe 20161122 */ unsigned int i,c; if(debug_var>=1) { tcleval( "puts $svg_colors"); } for(i=0;i> 16; svg_colors[i].green = (c & 0x00ff00) >> 8; svg_colors[i].blue = (c & 0x0000ff); } else if(dark_colorscheme) { svg_colors[i].red = 255; svg_colors[i].green = 255; svg_colors[i].blue = 255; } else { svg_colors[i].red = 0; svg_colors[i].green = 0; svg_colors[i].blue = 0; } if(debug_var>=1) { fprintf(errfp, "svg_colors: %d %d %d\n", svg_colors[i].red, svg_colors[i].green, svg_colors[i].blue); } } } void svg_draw(void) { double dx, dy; int c,i, textlayer; int filledrect; int old_grid; int modified_save; /* 20161121 */ char *tmpstring=NULL; const char *r; if(!plotfile[0]) { my_strdup(61, &tmpstring, "tk_getSaveFile -title {Select destination file} -initialdir $env(PWD)"); tcleval(tmpstring); r = tclresult(); my_free(963, &tmpstring); if(r[0]) my_strncpy(plotfile, r, S(plotfile)); else return; } restore_lw(); svg_colors=my_calloc(419, cadlayers, sizeof(Svg_color)); if(svg_colors==NULL){ fprintf(errfp, "svg_draw(): calloc error\n");tcleval( "exit"); } fill_svg_colors(); old_grid=draw_grid; draw_grid=0; dx=areax2-areax1; dy=areay2-areay1; dbg(1, "svg_draw(): dx=%g dy=%g\n", dx, dy); modified_save=modified; push_undo(); /* 20161121 */ trim_wires(); /* 20161121 add connection boxes on wires but undo at end */ if(plotfile[0]) fd=fopen(plotfile, "w"); else fd=fopen("plot.svg", "w"); my_strncpy(plotfile,"", S(plotfile)); fprintf(fd, "\n", dx, dy); fprintf(fd, "\n"); fclose(fd); draw_grid=old_grid; my_free(964, &svg_colors); pop_undo(0); /* 20161121 */ modified=modified_save; /* 20161121 */ }