/* 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");
fclose(fd);
draw_grid=old_grid;
my_free(964, &svg_colors);
pop_undo(0); /* 20161121 */
modified=modified_save; /* 20161121 */
}