/* File: draw.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" static double textx1,textx2,texty1,texty2; int textclip(int x1,int y1,int x2,int y2, double xa,double ya,double xb,double yb) /* check if some of (xa,ya-xb,yb) is inside (x1,y1-x2,y2) */ /* coordinates should be ordered, x1x2) return 0; else if (Y_TO_SCREEN(ya)>y2) return 0; else if (X_TO_SCREEN(xb)font; if(textfont && textfont[0]) { cairo_save(ctx); cairo_select_font_face (ctx, textfont, CAIRO_FONT_SLANT_NORMAL, CAIRO_FONT_WEIGHT_NORMAL); return 1; } return 0; } #else int set_text_custom_font(Text *txt) { return 0; } #endif #ifdef HAS_CAIRO void cairo_draw_string_line(cairo_t *ctx, char *s, double x, double y, double size, int rot, int flip, int lineno, double fontheight, double fontascent, double fontdescent, int llength) { double ix, iy; int rot1; cairo_text_extents_t ext; int line_delta; int line_offset; double xadvance; double lines; double vc; /* 20171121 vert correct */ /*int rx1, ry1, rx2, ry2, save_rot, save_flip; */ /* GC gcclear; */ if(s==NULL) return; if(llength==0) return; cairo_text_extents(ctx, s, &ext); xadvance = ext.x_advance; line_delta = lineno*fontheight*cairo_font_line_spacing; lines = (cairo_lines-1)*fontheight*cairo_font_line_spacing; line_offset=cairo_longest_line-xadvance; /* 20171215 NO! will skip drawing of long strings */ /* if(xadvance>14000) return; */ /* too big: close to short overflow */ ix=X_TO_SCREEN(x); iy=Y_TO_SCREEN(y); if(rot&1) { rot1=3; } else rot1=0; vc = cairo_vert_correct*mooz; /* converted to device (pixel) space */ if( rot==0 && flip==0) {iy+=line_delta+fontascent-vc;} else if(rot==1 && flip==0) {iy+=xadvance+line_offset;ix=ix-fontheight+fontascent+vc-lines+line_delta;} else if(rot==2 && flip==0) {iy=iy-fontheight-lines+line_delta+fontascent+vc; ix=ix-xadvance-line_offset;} else if(rot==3 && flip==0) {ix+=line_delta+fontascent-vc;} else if(rot==0 && flip==1) {ix=ix-xadvance-line_offset;iy+=line_delta+fontascent-vc;} else if(rot==1 && flip==1) {ix=ix-fontheight+line_delta-lines+fontascent+vc;} else if(rot==2 && flip==1) {iy=iy-fontheight-lines+line_delta+fontascent+vc;} else if(rot==3 && flip==1) {iy=iy+xadvance+line_offset;ix+=line_delta+fontascent-vc;} cairo_save(ctx); cairo_translate(ctx, ix, iy); cairo_rotate(ctx, XSCH_PI/2*rot1); /* fprintf(errfp, "string_line: |%s|, y_bearing: %f descent: %f ascent: %f height: %f\n", */ /* s, ext.y_bearing, fontdescent, fontascent, fontheight); */ cairo_move_to(ctx, 0,0); cairo_show_text(ctx, s); cairo_restore(ctx); } /* CAIRO version */ void draw_string(int layer, int what, char *s, int rot, int flip, int hcenter, int vcenter, double x, double y, double xscale, double yscale) { char *tt, *ss; char c; int lineno=0; double size; cairo_font_extents_t fext; int llength=0; (void)what; /* UNUSED in cairo version, avoid compiler warning */ if(s==NULL || !has_x ) return; size = xscale*52.*cairo_font_scale; /*fprintf(errfp, "size=%.16g\n", size*mooz); */ if(size*mooz<3.0) return; /* too small */ if(size*mooz>800) return; /* too big */ text_bbox(s, xscale, yscale, rot, flip, hcenter, vcenter, x,y, &textx1,&texty1,&textx2,&texty2); if(!textclip(areax1,areay1,areax2,areay2,textx1,texty1,textx2,texty2)) { return; } if(hcenter) { if(rot == 0 && flip == 0 ) { x=textx1;} if(rot == 1 && flip == 0 ) { y=texty1;} if(rot == 2 && flip == 0 ) { x=textx2;} if(rot == 3 && flip == 0 ) { y=texty2;} if(rot == 0 && flip == 1 ) { x=textx2;} if(rot == 1 && flip == 1 ) { y=texty2;} if(rot == 2 && flip == 1 ) { x=textx1;} if(rot == 3 && flip == 1 ) { y=texty1;} } if(vcenter) { if(rot == 0 && flip == 0 ) { y=texty1;} if(rot == 1 && flip == 0 ) { x=textx2;} if(rot == 2 && flip == 0 ) { y=texty2;} if(rot == 3 && flip == 0 ) { x=textx1;} if(rot == 0 && flip == 1 ) { y=texty1;} if(rot == 1 && flip == 1 ) { x=textx2;} if(rot == 2 && flip == 1 ) { y=texty2;} if(rot == 3 && flip == 1 ) { x=textx1;} } cairo_set_source_rgb(ctx, (double)xcolor_array[layer].red/65535.0, (double)xcolor_array[layer].green/65535.0, (double)xcolor_array[layer].blue/65535.0); cairo_set_source_rgb(save_ctx, (double)xcolor_array[layer].red/65535.0, (double)xcolor_array[layer].green/65535.0, (double)xcolor_array[layer].blue/65535.0); cairo_set_font_size (ctx, size*mooz); cairo_set_font_size (save_ctx, size*mooz); cairo_font_extents(ctx, &fext); /*fprintf(errfp, "cairo_draw_string(): s=%s lines=%d\n", s, cairo_lines); */ llength=0; tt=ss=s; for(;;) { c=*ss; if(c=='\n' || c==0) { *ss='\0'; /*fprintf(errfp, "cairo_draw_string(): tt=%s, longest line: %d\n", tt, cairo_longest_line); */ if(draw_window) cairo_draw_string_line(ctx, tt, x, y, size, rot, flip, lineno, fext.height, fext.ascent, fext.descent, llength); if(draw_pixmap) cairo_draw_string_line(save_ctx, tt, x, y, size, rot, flip, lineno, fext.height, fext.ascent, fext.descent, llength); lineno++; if(c==0) break; *ss='\n'; tt=ss+1; llength=0; } else { llength++; } ss++; } } #else /* !HAS_CAIRO */ /* no CAIRO version */ void draw_string(int layer, int what, char *str, int rot, int flip, int hcenter, int vcenter, double x1,double y1, double xscale, double yscale) { double a=0.0,yy; register double rx1=0,rx2=0,ry1=0,ry2=0; double curr_x1,curr_y1,curr_x2,curr_y2; register double zx1, invxscale; register int pos=0,pos2=0; register unsigned int cc; register double *char_ptr_x1,*char_ptr_y1,*char_ptr_x2,*char_ptr_y2; register int i,lines; if(str==NULL || !has_x ) return; dbg(2, "draw_string(): string=%s\n",str); if(xscale*FONTWIDTH*mooz<1) { dbg(1, "draw_string(): xscale=%.16g zoom=%.16g \n",xscale,zoom); return; } else { text_bbox(str, xscale, yscale, rot, flip, hcenter, vcenter, x1,y1, &textx1,&texty1,&textx2,&texty2); xscale*=nocairo_font_xscale; yscale*=nocairo_font_yscale; if(!textclip(areax1,areay1,areax2,areay2,textx1,texty1,textx2,texty2)) return; x1=textx1;y1=texty1; if(rot&1) {y1=texty2;rot=3;} else rot=0; flip = 0; yy=y1; invxscale=1/xscale; while(str[pos2]) { cc = (unsigned int)str[pos2++]; if(cc>127) cc= '?'; if(cc=='\n') { yy+=(FONTHEIGHT+FONTDESCENT+FONTWHITESPACE)* yscale; pos=0; a=0.0; continue; } lines=character[cc][0]*4; char_ptr_x1=character[cc]+1; char_ptr_y1=character[cc]+2; char_ptr_x2=character[cc]+3; char_ptr_y2=character[cc]+4; zx1=a+x1*invxscale; for(i=0;ilines[layer];j++) { line = (symptr->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); drawline(c,what, x0+x1, y0+y1, x0+x2, y0+y2); } for(j=0;j< symptr->polygons[layer];j++) /* 20171115 */ { polygon = (symptr->polygonptr[layer])[j]; { /* scope block so we declare some auxiliary arrays for coord transforms. 20171115 */ int k; double *x = my_malloc(34, sizeof(double) * polygon.points); double *y = my_malloc(35, sizeof(double) * polygon.points); for(k=0;karcs[layer];j++) { arc = (symptr->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); drawarc(c,what, x0+x1, y0+y1, arc.r, angle, arc.b, arc.fill); } if( (layer != PINLAYER || enable_layer[layer]) ) for(j=0;j< symptr->rects[layer];j++) { box = (symptr->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); drawrect(c,what, x0+x1, y0+y1, x0+x2, y0+y2); filledrect(c,what, x0+x1, y0+y1, x0+x2, y0+y2); } if( (layer==TEXTWIRELAYER && !(inst_ptr[n].flags&2) ) || (sym_txt && (layer==TEXTLAYER) && (inst_ptr[n].flags&2) ) ) { for(j=0;j< symptr->texts;j++) { text = symptr->txtptr[j]; if(text.xscale*FONTWIDTH*mooz<1) continue; text.txt_ptr= translate(n, text.txt_ptr); ROTATION(0.0,0.0,text.x0,text.y0,x1,y1); textlayer = c; if( !(c == PINLAYER && (inst_ptr[n].flags & 4))) { textlayer = symptr->txtptr[j].layer; if(textlayer < 0 || textlayer >= cadlayers) textlayer = c; } if((c == PINLAYER && inst_ptr[n].flags & 4) || enable_layer[textlayer]) { #ifdef HAS_CAIRO textfont = symptr->txtptr[j].font; if(textfont && textfont[0]) { cairo_save(ctx); cairo_save(save_ctx); cairo_select_font_face (ctx, textfont, CAIRO_FONT_SLANT_NORMAL, CAIRO_FONT_WEIGHT_NORMAL); cairo_select_font_face (save_ctx, textfont, CAIRO_FONT_SLANT_NORMAL, CAIRO_FONT_WEIGHT_NORMAL); } #endif draw_string(textlayer, what, text.txt_ptr, (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); #ifndef HAS_CAIRO drawrect(textlayer, END, 0.0, 0.0, 0.0, 0.0); drawline(textlayer, END, 0.0, 0.0, 0.0, 0.0); #endif #ifdef HAS_CAIRO if(textfont && textfont[0]) { cairo_restore(ctx); cairo_restore(save_ctx); } #endif } } } } void draw_temp_symbol(int what, GC gc, int n,int layer,int tmp_flip, int rot, double xoffset, double yoffset) /* draws current layer only, should be called within */ { /* a "for(i=0;ilines[layer];j++) { line = (symptr->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); drawtempline(gc,what, x0+x1, y0+y1, x0+x2, y0+y2); } for(j=0;j< symptr->polygons[layer];j++) /* 20171115 */ { /*fprintf(errfp, "draw_temp_symbol: polygon\n"); */ polygon = (symptr->polygonptr[layer])[j]; { /* scope block so we declare some auxiliary arrays for coord transforms. 20171115 */ int k; double *x = my_malloc(36, sizeof(double) * polygon.points); double *y = my_malloc(37, sizeof(double) * polygon.points); for(k=0;krects[layer];j++) { box = (symptr->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); drawtemprect(gc,what, x0+x1, y0+y1, x0+x2, y0+y2); } for(j=0;j< symptr->arcs[layer];j++) { arc = (symptr->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); drawtemparc(gc, what, x0+x1, y0+y1, arc.r, angle, arc.b); } if(layer==PROPERTYLAYER && sym_txt) { for(j=0;j< symptr->texts;j++) { text = symptr->txtptr[j]; if(text.xscale*FONTWIDTH*mooz<1) continue; text.txt_ptr= translate(n, text.txt_ptr); ROTATION(0.0,0.0,text.x0,text.y0,x1,y1); #ifdef HAS_CAIRO customfont = set_text_custom_font(&text); #endif if(text.txt_ptr[0]) draw_temp_string(gc, what, text.txt_ptr, (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); #ifdef HAS_CAIRO if(customfont) cairo_restore(ctx); #endif } } } void drawgrid() { double x,y; double delta,tmp; int i=0; if( !draw_grid || !has_x) return; delta=cadgrid*mooz; while(deltaareay1 && yareax1 && x=CADMAXGRIDPOINTS) { if(draw_window) XDrawPoints(display,window,gc[GRIDLAYER],gridpoint,i,CoordModeOrigin); if(draw_pixmap) XDrawPoints(display,save_pixmap,gc[GRIDLAYER],gridpoint,i,CoordModeOrigin); i=0; } gridpoint[i].x=(int)(x);gridpoint[i++].y=(int)(y); } } if(draw_window) XDrawPoints(display,window,gc[GRIDLAYER],gridpoint,i,CoordModeOrigin); if(draw_pixmap) XDrawPoints(display,save_pixmap,gc[GRIDLAYER],gridpoint,i,CoordModeOrigin); /* debug ... */ /* XFlush(display); */ } void drawline(int c, int what, double linex1, double liney1, double linex2, double liney2) { static int i = 0; #ifndef __unix__ int j = 0; #endif static XSegment r[CADDRAWBUFFERSIZE]; double x1,y1,x2,y2; register XSegment *rr; if(!has_x) return; rr=r; if(what & ADD) { if(i>=CADDRAWBUFFERSIZE) { #ifdef __unix__ if(draw_window) XDrawSegments(display, window, gc[c], rr,i); if(draw_pixmap) XDrawSegments(display, save_pixmap, gc[c], rr,i); #else for (j = 0; j < i; ++j) { if (draw_window) XDrawLine(display, window, gc[c], rr[j].x1, rr[j].y1, rr[j].x2, rr[j].y2); if (draw_pixmap) XDrawLine(display, save_pixmap, gc[c], rr[j].x1, rr[j].y1, rr[j].x2, rr[j].y2); } #endif i=0; } x1=X_TO_SCREEN(linex1); y1=Y_TO_SCREEN(liney1); x2=X_TO_SCREEN(linex2); y2=Y_TO_SCREEN(liney2); if(!only_probes && (x2-x1)< 0.3 && fabs(y2-y1) < 0.3) return; /* 20171206 */ if( clip(&x1,&y1,&x2,&y2) ) { rr[i].x1=(short)x1; rr[i].y1=(short)y1; rr[i].x2=(short)x2; rr[i].y2=(short)y2; i++; } } else if(what & NOW) { x1=X_TO_SCREEN(linex1); y1=Y_TO_SCREEN(liney1); x2=X_TO_SCREEN(linex2); y2=Y_TO_SCREEN(liney2); if(!only_probes && (x2-x1)< 0.3 && fabs(y2-y1)< 0.3) return; /* 20171206 */ if( clip(&x1,&y1,&x2,&y2) ) { if(draw_window) XDrawLine(display, window, gc[c], x1, y1, x2, y2); if(draw_pixmap) XDrawLine(display, save_pixmap, gc[c], x1, y1, x2, y2); } } else if(what & THICK) /* 26122004 */ { x1=X_TO_SCREEN(linex1); y1=Y_TO_SCREEN(liney1); x2=X_TO_SCREEN(linex2); y2=Y_TO_SCREEN(liney2); if(!only_probes && (x2-x1)< 0.3 && fabs(y2-y1)< 0.3) return; /* 20171206 */ if( clip(&x1,&y1,&x2,&y2) ) { XSetLineAttributes (display, gc[c], bus_width , LineSolid, CapRound , JoinRound); if(draw_window) XDrawLine(display, window, gc[c], x1, y1, x2, y2); if(draw_pixmap) XDrawLine(display, save_pixmap, gc[c], x1, y1, x2, y2); XSetLineAttributes (display, gc[c], lw, LineSolid, CapRound , JoinRound); } } else if(what & BEGIN) i=0; else if((what & END) && i) { #ifdef __unix__ if(draw_window) XDrawSegments(display, window, gc[c], rr,i); if(draw_pixmap) XDrawSegments(display, save_pixmap, gc[c], rr,i); #else for (j = 0; j < i; ++j) { if (draw_window) XDrawLine(display, window, gc[c], rr[j].x1, rr[j].y1, rr[j].x2, rr[j].y2); if (draw_pixmap) XDrawLine(display, save_pixmap, gc[c], rr[j].x1, rr[j].y1, rr[j].x2, rr[j].y2); } #endif i=0; } } void drawtempline(GC gc, int what, double linex1,double liney1,double linex2,double liney2) { static int i = 0; #ifndef __unix__ int j = 0; #endif static XSegment r[CADDRAWBUFFERSIZE]; double x1,y1,x2,y2; if(!has_x) return; if(what & ADD) { if(i>=CADDRAWBUFFERSIZE) { #ifdef __unix__ XDrawSegments(display, window, gc, r,i); #else for (j = 0; j < i; ++j) { XDrawLine(display, window, gc, r[j].x1, r[j].y1, r[j].x2, r[j].y2); } #endif i=0; } x1=X_TO_SCREEN(linex1); y1=Y_TO_SCREEN(liney1); x2=X_TO_SCREEN(linex2); y2=Y_TO_SCREEN(liney2); if( clip(&x1,&y1,&x2,&y2) ) { r[i].x1=(short)x1; r[i].y1=(short)y1; r[i].x2=(short)x2; r[i].y2=(short)y2; i++; } } else if(what & NOW) { x1=X_TO_SCREEN(linex1); y1=Y_TO_SCREEN(liney1); x2=X_TO_SCREEN(linex2); y2=Y_TO_SCREEN(liney2); if( clip(&x1,&y1,&x2,&y2) ) { XDrawLine(display, window, gc, x1, y1, x2, y2); } } else if(what & THICK) /* 26122004 */ { x1=X_TO_SCREEN(linex1); y1=Y_TO_SCREEN(liney1); x2=X_TO_SCREEN(linex2); y2=Y_TO_SCREEN(liney2); if( clip(&x1,&y1,&x2,&y2) ) { XSetLineAttributes (display, gc, bus_width, LineSolid, CapRound , JoinRound); /* 20150410 */ XDrawLine(display, window, gc, x1, y1, x2, y2); if(gc==gctiled) XSetLineAttributes (display, gc, lw, LineSolid, CapRound , JoinRound); else XSetLineAttributes (display, gc, lw, LineSolid, CapRound , JoinRound); } } else if(what & BEGIN) i=0; else if((what & END) && i) { #ifdef __unix__ XDrawSegments(display, window, gc, r,i); #else for (j = 0; j < i; ++j) { XDrawLine(display, window, gc, r[j].x1, r[j].y1, r[j].x2, r[j].y2); } #endif i=0; } } void drawtemparc(GC gc, int what, double x, double y, double r, double a, double b) { static int i=0; static XArc arc[CADDRAWBUFFERSIZE]; double x1, y1, x2, y2; /* arc bbox */ double xx1, yy1, xx2, yy2; /* complete circle bbox in screen coords */ if(!has_x) return; if(what & ADD) { if(i>=CADDRAWBUFFERSIZE) { XDrawArcs(display, window, gc, arc,i); i=0; } xx1=X_TO_SCREEN(x-r); yy1=Y_TO_SCREEN(y-r); xx2=X_TO_SCREEN(x+r); yy2=Y_TO_SCREEN(y+r); arc_bbox(x, y, r, a, b, &x1,&y1,&x2,&y2); x1=X_TO_SCREEN(x1); y1=Y_TO_SCREEN(y1); x2=X_TO_SCREEN(x2); y2=Y_TO_SCREEN(y2); if( rectclip(areax1,areay1,areax2,areay2,&x1,&y1,&x2,&y2) ) { arc[i].x=(short)xx1; arc[i].y=(short)yy1; arc[i].width= (unsigned short)(xx2 - xx1); arc[i].height=(unsigned short)(yy2 - yy1); arc[i].angle1 = a*64; arc[i].angle2 = b*64; i++; } } else if(what & NOW) { xx1=X_TO_SCREEN(x-r); yy1=Y_TO_SCREEN(y-r); xx2=X_TO_SCREEN(x+r); yy2=Y_TO_SCREEN(y+r); arc_bbox(x, y, r, a, b, &x1,&y1,&x2,&y2); x1=X_TO_SCREEN(x1); y1=Y_TO_SCREEN(y1); x2=X_TO_SCREEN(x2); y2=Y_TO_SCREEN(y2); if( rectclip(areax1,areay1,areax2,areay2,&x1,&y1,&x2,&y2) ) { XDrawArc(display, window, gc, xx1, yy1, xx2-xx1, yy2-yy1, a*64, b*64); } } else if(what & BEGIN) i=0; else if((what & END) && i) { XDrawArcs(display, window, gc, arc,i); i=0; } } /* x1,y1: start; x2,y2: end; x3,y3: way point */ void arc_3_points(double x1, double y1, double x2, double y2, double x3, double y3, double *x, double *y, double *r, double *a, double *b) { double A, B, C; double c, s; /* s = signed_area, if > 0 : clockwise in xorg coordinate space */ s = x3*y2-x2*y3 + x2*y1 -x1*y2 + x1*y3-x3*y1; A = x1*(y2-y3) - y1*(x2-x3) + x2*y3 - x3*y2; B = (x1*x1+y1*y1)*(y3-y2)+(x2*x2+y2*y2)*(y1-y3) + (x3*x3+y3*y3)*(y2-y1); C = (x1*x1+y1*y1)*(x2-x3)+(x2*x2+y2*y2)*(x3-x1) + (x3*x3+y3*y3)*(x1-x2); /* printf("s=%g\n", s); */ *x = -B/2./A; *y = -C/2./A; *r = sqrt( (*x-x1)*(*x-x1) + (*y-y1)*(*y-y1) ); *a = fmod(atan2(*y-y1 ,x1-*x )*180./XSCH_PI, 360.); if(*a<0.) *a+=360.; *b = fmod(atan2(*y-y2 ,x2-*x )*180./XSCH_PI, 360.); if(*b<0.) *b+=360.; if(s<0.) { /* counter clockwise, P1, P3, P2 */ *b = fmod(*b-*a, 360.); if(*b<0) *b+=360.; if(*b==0) *b=360.; } else if(s>0.) { /* clockwise, P2, P3, P1 */ c = fmod(*a-*b, 360.); if(c<0) c+=360.; if(*b==0) *b=360.; *a = *b; *b = c; } else { *r = -1.0; /* no circle thru aligned points */ } } void filledarc(int c, int what, double x, double y, double r, double a, double b) { static int i=0; static XArc arc[CADDRAWBUFFERSIZE]; double x1, y1, x2, y2; /* arc bbox */ double xx1, yy1, xx2, yy2; /* complete circle bbox in screen coords */ if(!has_x) return; if(what & ADD) { if(i>=CADDRAWBUFFERSIZE) { if(draw_window) XFillArcs(display, window, gc[c], arc,i); if(draw_pixmap) XFillArcs(display, save_pixmap, gc[c], arc,i); i=0; } xx1=X_TO_SCREEN(x-r); yy1=Y_TO_SCREEN(y-r); xx2=X_TO_SCREEN(x+r); yy2=Y_TO_SCREEN(y+r); arc_bbox(x, y, r, a, b, &x1,&y1,&x2,&y2); x1=X_TO_SCREEN(x1); y1=Y_TO_SCREEN(y1); x2=X_TO_SCREEN(x2); y2=Y_TO_SCREEN(y2); if( rectclip(areax1,areay1,areax2,areay2,&x1,&y1,&x2,&y2) ) { arc[i].x=(short)xx1; arc[i].y=(short)yy1; arc[i].width =(unsigned short)(xx2 - xx1); arc[i].height=(unsigned short)(yy2 - yy1); arc[i].angle1 = a*64; arc[i].angle2 = b*64; i++; } } else if(what & NOW) { xx1=X_TO_SCREEN(x-r); yy1=Y_TO_SCREEN(y-r); xx2=X_TO_SCREEN(x+r); yy2=Y_TO_SCREEN(y+r); arc_bbox(x, y, r, a, b, &x1,&y1,&x2,&y2); x1=X_TO_SCREEN(x1); y1=Y_TO_SCREEN(y1); x2=X_TO_SCREEN(x2); y2=Y_TO_SCREEN(y2); if( rectclip(areax1,areay1,areax2,areay2,&x1,&y1,&x2,&y2) ) { if(draw_window) XFillArc(display, window, gc[c], xx1, yy1, xx2-xx1, yy2-yy1, a*64, b*64); if(draw_pixmap) XFillArc(display, save_pixmap, gc[c], xx1, yy1, xx2-xx1, yy2-yy1, a*64, b*64); } } else if(what & BEGIN) i=0; else if((what & END) && i) { if(draw_window) XFillArcs(display, window, gc[c], arc,i); if(draw_pixmap) XFillArcs(display, save_pixmap, gc[c], arc,i); i=0; } } void drawarc(int c, int what, double x, double y, double r, double a, double b, int arc_fill) { static int i=0; static XArc arc[CADDRAWBUFFERSIZE]; double x1, y1, x2, y2; /* arc bbox */ double xx1, yy1, xx2, yy2; /* complete circle bbox in screen coords */ if(arc_fill) what = NOW; if(!has_x) return; if(what & ADD) { if(i>=CADDRAWBUFFERSIZE) { if(draw_window) XDrawArcs(display, window, gc[c], arc,i); if(draw_pixmap) XDrawArcs(display, save_pixmap, gc[c], arc,i); i=0; } xx1=X_TO_SCREEN(x-r); yy1=Y_TO_SCREEN(y-r); xx2=X_TO_SCREEN(x+r); yy2=Y_TO_SCREEN(y+r); arc_bbox(x, y, r, a, b, &x1,&y1,&x2,&y2); x1=X_TO_SCREEN(x1); y1=Y_TO_SCREEN(y1); x2=X_TO_SCREEN(x2); y2=Y_TO_SCREEN(y2); if( rectclip(areax1,areay1,areax2,areay2,&x1,&y1,&x2,&y2) ) { arc[i].x=(short)xx1; arc[i].y=(short)yy1; arc[i].width =(unsigned short)(xx2 - xx1); arc[i].height=(unsigned short)(yy2 - yy1); arc[i].angle1 = a*64; arc[i].angle2 = b*64; i++; } } else if(what & NOW) { xx1=X_TO_SCREEN(x-r); yy1=Y_TO_SCREEN(y-r); xx2=X_TO_SCREEN(x+r); yy2=Y_TO_SCREEN(y+r); if(arc_fill) arc_bbox(x, y, r, 0, 360, &x1,&y1,&x2,&y2); else arc_bbox(x, y, r, a, b, &x1,&y1,&x2,&y2); x1=X_TO_SCREEN(x1); y1=Y_TO_SCREEN(y1); x2=X_TO_SCREEN(x2); y2=Y_TO_SCREEN(y2); if( rectclip(areax1,areay1,areax2,areay2,&x1,&y1,&x2,&y2) ) { if(draw_window) { XDrawArc(display, window, gc[c], xx1, yy1, xx2-xx1, yy2-yy1, a*64, b*64); } if(draw_pixmap) { XDrawArc(display, save_pixmap, gc[c], xx1, yy1, xx2-xx1, yy2-yy1, a*64, b*64); } if(fill && fill_type[c]){ if(arc_fill) { if(draw_window) XFillArc(display, window, gcstipple[c], xx1, yy1, xx2-xx1, yy2-yy1, a*64, b*64); if(draw_pixmap) XFillArc(display, save_pixmap, gcstipple[c], xx1, yy1, xx2-xx1, yy2-yy1, a*64, b*64); } } } } else if(what & BEGIN) i=0; else if((what & END) && i) { if(draw_window) XDrawArcs(display, window, gc[c], arc,i); if(draw_pixmap) XDrawArcs(display, save_pixmap, gc[c], arc,i); i=0; } } void filledrect(int c, int what, double rectx1,double recty1,double rectx2,double recty2) { static int i=0; static XRectangle r[CADDRAWBUFFERSIZE]; double x1,y1,x2,y2; if(!has_x) return; if(!fill || !fill_type[c]) return; if(what & NOW) { x1=X_TO_SCREEN(rectx1); y1=Y_TO_SCREEN(recty1); x2=X_TO_SCREEN(rectx2); y2=Y_TO_SCREEN(recty2); if(!only_probes && (x2-x1)< 2 && (y2-y1)< 2) return; /* 20171206 */ if( rectclip(areax1,areay1,areax2,areay2,&x1,&y1,&x2,&y2) ) { if(draw_window) XFillRectangle(display, window, gcstipple[c], (int)x1, (int)y1, (unsigned int)x2 - (unsigned int)x1, (unsigned int)y2 - (unsigned int)y1); if(draw_pixmap) XFillRectangle(display, save_pixmap,gcstipple[c], (int)x1, (int)y1, (unsigned int)x2 - (unsigned int)x1, (unsigned int)y2 - (unsigned int)y1); } } else if(what & BEGIN) i=0; else if(what & ADD) { if(i>=CADDRAWBUFFERSIZE) { if(draw_window) XFillRectangles(display, window, gcstipple[c], r,i); if(draw_pixmap) XFillRectangles(display, save_pixmap, gcstipple[c], r,i); i=0; } x1=X_TO_SCREEN(rectx1); y1=Y_TO_SCREEN(recty1); x2=X_TO_SCREEN(rectx2); y2=Y_TO_SCREEN(recty2); if(!only_probes && (x2-x1)< 2 && (y2-y1)< 2) return; /* 20171206 */ if( rectclip(areax1,areay1,areax2,areay2,&x1,&y1,&x2,&y2) ) { r[i].x=(short)x1; r[i].y=(short)y1; r[i].width=(unsigned short)x2-r[i].x; r[i].height=(unsigned short)y2-r[i].y; i++; } } else if((what & END) && i) { if(draw_window) XFillRectangles(display, window, gcstipple[c], r,i); if(draw_pixmap) XFillRectangles(display, save_pixmap, gcstipple[c], r,i); i=0; } } void polygon_bbox(double *x, double *y, int points, double *bx1, double *by1, double *bx2, double *by2) { int j; for(j=0; j *bx2) *bx2 = x[j]; if(j==0 || y[j] > *by2) *by2 = y[j]; } } void arc_bbox(double x, double y, double r, double a, double b, double *bx1, double *by1, double *bx2, double *by2) { double x2, y2, x3, y3; int aa, bb, i; if(b==360.) { *bx1 = x-r; *by1 = y-r; *bx2 = x+r; *by2 = y+r; return; } a = fmod(a, 360.); if(a<0) a+=360.; aa = (int)(ceil(a/90.))*90; bb = (int)(floor((a+b)/90.))*90; /* printf("arc_bbox(): aa=%d bb=%d\n", aa, bb); */ x2 = x + r * cos(a * XSCH_PI/180.); y2 = y - r * sin(a * XSCH_PI/180.); x3 = x + r * cos((a+b) * XSCH_PI/180.); y3 = y - r * sin((a+b) * XSCH_PI/180.); /* *bx1 = (x2 < x ) ? x2 : x; */ *bx1 = x2; if(x3 < *bx1) *bx1 = x3; /* *bx2 = (x2 > x ) ? x2 : x; */ *bx2 = x2; if(x3 > *bx2) *bx2 = x3; /* *by1 = (y2 < y ) ? y2 : y; */ *by1 = y2; if(y3 < *by1) *by1 = y3; /* *by2 = (y2 > y ) ? y2 : y; */ *by2 = y2; if(y3 > *by2) *by2 = y3; for(i=aa; i<=bb; i++) { if(i%360==0) { *bx2 = x + r; } if(i%360==90) { *by1 = y - r; } if(i%360==180) { *bx1 = x - r; } if(i%360==270) { *by2 = y + r; } } /* printf("arc_bbox(): bx1=%g by1=%g bx2=%g by2=%g\n", *bx1, *by1, *bx2, *by2); */ } /* Convex Nonconvex Complex */ #define Polygontype Nonconvex /* 20180914 added fill param */ void drawpolygon(int c, int what, double *x, double *y, int points, int poly_fill) { double x1,y1,x2,y2; XPoint *p; int i; if(!has_x) return; polygon_bbox(x, y, points, &x1,&y1,&x2,&y2); x1=X_TO_SCREEN(x1); y1=Y_TO_SCREEN(y1); x2=X_TO_SCREEN(x2); y2=Y_TO_SCREEN(y2); if( !rectclip(areax1,areay1,areax2,areay2,&x1,&y1,&x2,&y2) ) { return; } if( !only_probes && (x2-x1)<0.3 && (y2-y1)<0.3) return; /* 20171206 */ p = my_malloc(38, sizeof(XPoint) * points); for(i=0;i=CADDRAWBUFFERSIZE) { if(draw_window) XDrawRectangles(display, window, gc[c], r,i); if(draw_pixmap) XDrawRectangles(display, save_pixmap, gc[c], r,i); i=0; } x1=X_TO_SCREEN(rectx1); y1=Y_TO_SCREEN(recty1); x2=X_TO_SCREEN(rectx2); y2=Y_TO_SCREEN(recty2); if(!only_probes && (x2-x1)< 0.3 && (y2-y1)< 0.3) return; /* 20171206 */ if( rectclip(areax1,areay1,areax2,areay2,&x1,&y1,&x2,&y2) ) { r[i].x=(short)x1; r[i].y=(short)y1; r[i].width=(unsigned short)x2-r[i].x; r[i].height=(unsigned short)y2-r[i].y; i++; } } else if((what & END) && i) { if(draw_window) XDrawRectangles(display, window, gc[c], r,i); if(draw_pixmap) XDrawRectangles(display, save_pixmap, gc[c], r,i); i=0; } } void drawtemprect(GC gc, int what, double rectx1,double recty1,double rectx2,double recty2) { static int i=0; static XRectangle r[CADDRAWBUFFERSIZE]; double x1,y1,x2,y2; if(!has_x) return; if(what & NOW) { x1=X_TO_SCREEN(rectx1); y1=Y_TO_SCREEN(recty1); x2=X_TO_SCREEN(rectx2); y2=Y_TO_SCREEN(recty2); if( (x2-x1)< 0.3 && (y2-y1)< 0.3) return; /* 20171206 */ if( rectclip(areax1,areay1,areax2,areay2,&x1,&y1,&x2,&y2) ) { XDrawRectangle(display, window, gc, (int)x1, (int)y1, (unsigned int)x2 - (unsigned int)x1, (unsigned int)y2 - (unsigned int)y1); } } else if(what & BEGIN) i=0; else if(what & ADD) { if(i>=CADDRAWBUFFERSIZE) { XDrawRectangles(display, window, gc, r,i); i=0; } x1=X_TO_SCREEN(rectx1); y1=Y_TO_SCREEN(recty1); x2=X_TO_SCREEN(rectx2); y2=Y_TO_SCREEN(recty2); if( (x2-x1)< 0.3 && (y2-y1)< 0.3) return; /* 20171206 */ if( rectclip(areax1,areay1,areax2,areay2,&x1,&y1,&x2,&y2) ) { r[i].x=(short)x1; r[i].y=(short)y1; r[i].width=(unsigned short)x2-r[i].x; r[i].height=(unsigned short)y2-r[i].y; i++; } } else if((what & END) && i) { XDrawRectangles(display, window, gc, r,i); i=0; } } void draw(void) { /* inst_ptr and wire hash iterator 20171224 */ double x1, y1, x2, y2; struct instentry *instanceptr; struct wireentry *wireptr; int ii; char *type=NULL; /* 20180109 */ int use_hash; register int c,i; register Instdef *symptr; /* 20150408 */ int textlayer; /* 20171112 */ #ifdef HAS_CAIRO char *textfont; #endif if(no_draw) return; rebuild_selected_array(); if(has_x) { if(draw_pixmap) XFillRectangle(display, save_pixmap, gc[BACKLAYER], areax1, areay1, areaw, areah); if(draw_window) XFillRectangle(display, window, gc[BACKLAYER], areax1, areay1, areaw, areah); dbg(2, "draw(): window: %d %d %d %d\n",areax1, areay1, areax2, areay2); drawgrid(); x1 = X_TO_XSCHEM(areax1); y1 = Y_TO_XSCHEM(areay1); x2 = X_TO_XSCHEM(areax2); y2 = Y_TO_XSCHEM(areay2); use_hash = (lastwire> 2000 || lastinst > 2000 ) && (x2 - x1 < ITERATOR_THRESHOLD); if(use_hash) { hash_instances(); hash_wires(); } if(!only_probes) { /* 20110112 */ dbg(3, "draw(): check4\n"); for(c=0;cn; ptr = inst_ptr[i].ptr; if( ptr !=-1) { /* 20180921 */ symptr = ptr+instdef; if( c==0 || /*20150408 draw_symbol call is needed on layer 0 to avoid redundant work (outside check) */ symptr->lines[c] || /* 20150408 */ symptr->arcs[c] || symptr->rects[c] || /* 20150408 */ symptr->polygons[c] || /* 20150408 */ ((c==TEXTWIRELAYER || c==TEXTLAYER) && symptr->texts)) { /* 20150408 */ type = symptr->type; if(!( hilight_nets && type && ( ( !(strcmp(type,"label") && strcmp(type,"ipin") && strcmp(type,"iopin") && strcmp(type,"opin")) && bus_hilight_lookup( get_tok_value(inst_ptr[i].prop_ptr,"lab",0) , 0, XLOOKUP ) ) || ( (strcmp(type,"label") && strcmp(type,"ipin") && strcmp(type,"iopin") && strcmp(type,"opin")) && (inst_ptr[i].flags & 4) ) ) ) ) { draw_symbol(ADD, c, instanceptr->n,c,0,0,0.0,0.0); } } /* 20150408 */ } /*if( ptr !=-1) */ } /* --------------------------------- /20171224 */ } else { for(i=0;ilines[c] || /* 20150408 */ symptr->arcs[c] || symptr->rects[c] || /* 20150408 */ symptr->polygons[c] || /* 20150408 */ ((c==TEXTWIRELAYER || c==TEXTLAYER) && symptr->texts)) { /* 20150408 */ type = (inst_ptr[i].ptr+instdef)->type; if(!( hilight_nets && type && ( ( !(strcmp(type,"label") && strcmp(type,"ipin") && strcmp(type,"iopin") && strcmp(type,"opin")) && bus_hilight_lookup( get_tok_value(inst_ptr[i].prop_ptr,"lab",0) , 0, XLOOKUP ) ) || ( (strcmp(type,"label") && strcmp(type,"ipin") && strcmp(type,"iopin") && strcmp(type,"opin")) && (inst_ptr[i].flags & 4) ) ) ) ) { draw_symbol(ADD, c, i,c,0,0,0.0,0.0); } } /* 20150408 */ } } filledrect(c, END, 0.0, 0.0, 0.0, 0.0); drawarc(c, END, 0.0, 0.0, 0.0, 0.0, 0.0, 0); drawrect(c, END, 0.0, 0.0, 0.0, 0.0); drawline(c, END, 0.0, 0.0, 0.0, 0.0); } if(draw_single_layer==-1 || draw_single_layer==WIRELAYER){ /* 20151117 */ if(use_hash) { dbg(3, "using spatial hash table iterator\n"); /*loop thru all squares that intersect drawing area */ for(init_wire_iterator(x1, y1, x2, y2); ( wireptr = wire_iterator_next() ) ;) { ii=wireptr->n; if(wire[ii].bus) { drawline(WIRELAYER, THICK, wire[ii].x1,wire[ii].y1,wire[ii].x2,wire[ii].y2); } else drawline(WIRELAYER, ADD, wire[ii].x1,wire[ii].y1,wire[ii].x2,wire[ii].y2); } } else { for(i=0;i= cadlayers) textlayer = TEXTLAYER; dbg(1, "draw(): drawing string %d = %s\n",i, textelement[i].txt_ptr); #ifdef HAS_CAIRO textfont = textelement[i].font; /* 20171206 */ if(textfont && textfont[0]) { cairo_save(ctx); cairo_save(save_ctx); cairo_select_font_face (ctx, textfont, CAIRO_FONT_SLANT_NORMAL, CAIRO_FONT_WEIGHT_NORMAL); cairo_select_font_face (save_ctx, textfont, CAIRO_FONT_SLANT_NORMAL, CAIRO_FONT_WEIGHT_NORMAL); } #endif draw_string(textlayer, ADD, textelement[i].txt_ptr, textelement[i].rot, textelement[i].flip, textelement[i].hcenter, textelement[i].vcenter, textelement[i].x0,textelement[i].y0, textelement[i].xscale, textelement[i].yscale); #ifdef HAS_CAIRO if(textfont && textfont[0]) { cairo_restore(ctx); cairo_restore(save_ctx); } #endif #ifndef HAS_CAIRO drawrect(textlayer, END, 0.0, 0.0, 0.0, 0.0); drawline(textlayer, END, 0.0, 0.0, 0.0, 0.0); #endif } } } /* !only_probes, 20110112 */ draw_hilight_net(draw_window); if(!draw_window) { XCopyArea(display, save_pixmap, window, gctiled, xrect[0].x, xrect[0].y, xrect[0].width, xrect[0].height, xrect[0].x, xrect[0].y); /* 20181009 */ } draw_selection(gc[SELLAYER], 0); /* 20181009 moved outside of cadlayers loop */ dbg(1, "draw(): lw=%d\n",lw); } /* if(has_x) */ } #ifndef __unix__ /* place holder for Windows to show that these XLib functions are not supported in Windows. */ int XSetClipRectangles(register Display* dpy, GC gc, int clip_x_origin, int clip_y_origin, XRectangle* rectangles, int n, int ordering) { return 0; } int XSetTile(Display* display, GC gc, Pixmap save_pixmap) { return 0; } #endif