// graph.c // // by John D. de Boer #include "common.h" #include "cstring.h" #include "cyber.h" #include "disk.h" #include "floating.h" #include "frame.h" #include "graph.h" extern colour QPal[]; // void savegraphics(window *W) { if (!W || !W->q2d) return; CGContextSaveGState(W->q2d); } void restoregraphics(window *W) { if (!W || !W->q2d) return; CGContextRestoreGState(W->q2d); } void transform(window *W, rect Src, rect Dest) { if (!W || !W->q2d) return; CGContextTranslateCTM(W->q2d,left(Dest) - left(Src),bottom(Dest) - bottom(Src)); CGContextScaleCTM(W->q2d,width(Dest) / width(Src),height(Dest) / height(Src));} void antialias(window *W, bool Anti) { if (!W || !W->q2d) return; CGContextSetShouldAntialias(W->q2d,Anti); } // Colours void pencolour(window *W, const colour *C) { if (!W || !W->q2d || !C) return; CGContextSetStrokeColor(W->q2d,C->c); } void penindex(window *W, int COLOUR) { if (!W || !W->q2d || !range(COLOUR,MAXCOLOUR)) return; CGContextSetStrokeColor(W->q2d,QPal[COLOUR].c); } void fillcolour(window *W, const colour *C) { if (!W || !W->q2d || !C) return; CGContextSetFillColor(W->q2d,C->c); } void fillindex(window *W, int COLOUR) { if (!W || !W->q2d || !range(COLOUR,MAXCOLOUR)) return; CGContextSetFillColor(W->q2d,QPal[COLOUR].c); } void penwidth(window *W, float Width) { if (!W || !W->q2d) return; CGContextSetLineWidth(W->q2d,Width); } // Paths void beginpath(window *W) { if (!W || !W->q2d) return; CGContextBeginPath(W->q2d); } void move(window *W, float DX, float DY) { CGPoint P; if (!W || !W->q2d) return; P=CGContextGetPathCurrentPoint(W->q2d); CGContextMoveToPoint(W->q2d,P.x + DX,P.y + DY); } void moveto(window *W, float X, float Y) { if (!W || !W->q2d) return; CGContextMoveToPoint(W->q2d,X,Y); } void movept(window *W, point P) { if (!W || !W->q2d) return; CGContextMoveToPoint(W->q2d,P.x,P.y); } void line(window *W, float DX, float DY) { CGPoint P; if (!W || !W->q2d) return; P=CGContextGetPathCurrentPoint(W->q2d); CGContextAddLineToPoint(W->q2d,P.x + DX,P.y + DY); } void lineto(window *W, float X, float Y) { if (!W || !W->q2d) return; CGContextAddLineToPoint(W->q2d,X,Y); } void linept(window *W, point P) { if (!W || !W->q2d) return; CGContextAddLineToPoint(W->q2d,P.x,P.y); } void line2(window *W, float A, float B, float C, float D) { line(W,A,B); line(W,C,D); } void line3(window *W, float A, float B, float C, float D, float E, float F) { line(W,A,B); line(W,C,D); line(W,E,F); } void line4(window *W, float A, float B, float C, float D, float E, float F, float G, float H) { line(W,A,B); line(W,C,D); line(W,E,F); line(W,G,H); } void line5(window *W, float A, float B, float C, float D, float E, float F, float G, float H, float I, float J) { line(W,A,B); line(W,C,D); line(W,E,F); line(W,G,H); line(W,I,J); } void addrect(window *W, rect R) { if (!W || !W->q2d) return; CGContextAddRect(W->q2d,R); } void addcircle(window *W, float X, float Y, float Rad) { if (!W || !W->q2d) return; CGContextAddArc(W->q2d,X,Y,Rad,0.0,twopi,0); } void addellipse(window *W, rect R) { // only works in 10.4 if (!W || !W->q2d) return; CGContextAddEllipseInRect(W->q2d,R); } void stroke(window *W) { if (!W || !W->q2d) return; CGContextStrokePath(W->q2d); } void fill(window *W) { if (!W || !W->q2d) return; CGContextEOFillPath(W->q2d); } void clip(window *W) { if (!W || !W->q2d) return; CGContextClip(W->q2d); } void framerect(window *W, rect R) { if (!W || !W->q2d) return; CGContextStrokeRect(W->q2d,R); } void fillrect(window *W, rect R) { if (!W || !W->q2d) return; CGContextFillRect(W->q2d,R); } void cliprect(window *W, rect R) { if (!W || !W->q2d) return; CGContextClipToRect(W->q2d,R); } static void roundrectpath(window *W, rect R, float Radius) { float X1,X2,Y1,Y2; if (!W || !W->q2d) return; Radius=flsr(Radius,height(R) / 2.0); Radius=flsr(Radius,width(R) / 2.0); X1=left(R); X2=right(R); Y1=bottom(R); Y2=top(R); CGContextMoveToPoint(W->q2d,X1 + Radius,Y1); CGContextAddArcToPoint(W->q2d,X2,Y1,X2,Y2,Radius); CGContextAddArcToPoint(W->q2d,X2,Y2,X1,Y2,Radius); CGContextAddArcToPoint(W->q2d,X1,Y2,X1,Y1,Radius); CGContextAddArcToPoint(W->q2d,X1,Y1,X2,Y1,Radius); } void frameroundrect(window *W, rect R, float Radius) { if (!W) return; beginpath(W); roundrectpath(W,R,Radius); stroke(W); } void fillroundrect(window *W, rect R, float Radius) { if (!W) return; beginpath(W); roundrectpath(W,R,Radius); fill(W); } // Text void textfont(window *W, const char *Font, float Size) { if (!W || !W->q2d || !Font) return; CGContextSelectFont(W->q2d,Font,Size,kCGEncodingMacRoman); } void textsize(window *W, float S) { if (!W || !W->q2d) return; CGContextSetFontSize(W->q2d,S); } float textwidth(window *W, const char *S) { CGPoint P1,P2; if (!W || !W->q2d || !S || !*S) return 0.0; P1=CGContextGetTextPosition(W->q2d); CGContextSetTextDrawingMode(W->q2d,kCGTextInvisible); CGContextShowText(W->q2d,S,length(S)); CGContextSetTextDrawingMode(W->q2d,kCGTextFill); // doesn't restore P2=CGContextGetTextPosition(W->q2d); CGContextSetTextPosition(W->q2d,P1.x,P1.y); return P2.x - P1.x; } void text(window *W, const char *S) { if (!W || !W->q2d || !S || !*S) return; CGContextShowText(W->q2d,S,length(S)); } void textold(window *W, string S) { text(W,S); old(S); } void drawtext(window *W, float X, float Y, const char *S) { if (!W || !W->q2d) return; CGContextSetTextPosition(W->q2d,X,Y); text(W,S); } void drawtextold(window *W, float X, float Y, string S) { drawtext(W,X,Y,S); old(S); } void textcentre(window *W, float X, float Y, const char *S) { drawtext(W,X - (textwidth(W,S) / 2.0),Y,S); } void textleft(window *W, float X, float Y, const char *S) { drawtext(W,X - textwidth(W,S),Y,S); } void textint(window *W, long N) { textold(W,fig(N)); } static void textexponent(window *W, int EXP) { float Size,Horz; if (!W || !W->q2d) return; savegraphics(W); Size=10.0;//GetPortTextSize(W->q2d); Horz= Size / 4.0; /*Move(HORZ,-0.2 * SIZE); TextSize(0.75 * SIZE); drawstr("x"); Move(HORZ, 0.2 * SIZE); TextSize(SIZE); drawstr("10"); Move(HORZ,-0.4 * SIZE); TextSize(0.75 * SIZE); drawint(EXP); Move(HORZ, 0.4 * SIZE); TextSize(SIZE);*/ text(W," x 10^"); textint(W,EXP); restoregraphics(W); } void textreal(window *W, float X, int PLACES) { short E=0; if (!W || !W->q2d) return; textold(W,engineeringrep(X,PLACES,&E)); if (E) textexponent(W,E); } void textfixed(window *W, float X, int LEFT, int RIGHT) { textold(W,fixedstring(X,LEFT,RIGHT)); } void drawchar(window *W, char C) { char S[2]; S[0]=C; S[1]=0; text(W,S); } void boldtext(window *W, float X, float Y, const char *S, float Size) { float Sh; Sh= 0.03 * Size; drawtext(W,X,Y,S); drawtext(W,X + Sh,Y,S); drawtext(W,X,Y + Sh,S); drawtext(W,X + Sh,Y + Sh,S); } static char convgreek(char C) { switch (C) { case 'a': return 95; // alpha case 'b': return 96; // beta case 'g': return 97; // gamma case 'd': return 98; // delta case 'e': return 161; // epsilon case 'z': return 99; // zeta case 'h': return 100; // eta case 'q': return 101; // theta case 'i': return 102; // iota case 'k': return 103; // kappa case 'l': return 104; // lambda case 'm': return 43; // mu case 'n': return 105; // nu case 'x': return 106; // xi case 'o': return 107; // omicron case 'p': return 47; // pi case 'r': return 108; // rho case 's': return 109; // sigma case 't': return 111; // tau case 'u': return 112; // upsilon case 'f': return 113; // phi case 'c': return 114; // chi case 'y': return 115; // psi case 'w': return 116; // omega } return C; } // static char *GA="abgdezhqiklmnxoprstufcyw"; void drawgreekletter(window *W, float Size, char C) { char G; if (!W) return; G=convgreek(C); savegraphics(W); CGContextSelectFont(W->q2d,"Symbol",1.25 * Size,kCGEncodingFontSpecific); CGContextShowText(W->q2d,&G,1); restoregraphics(W); } // Images void drawpicture(window *W, picture P, rect R) { if (!W || !W->q2d || !P) return; CGContextDrawImage(W->q2d,R,P); } void drawpictureclip(window *W, picture P, rect R, rect Clip) { if (!W || !W->q2d || !P) return; savegraphics(W); cliprect(W,Clip); CGContextDrawImage(W->q2d,R,P); restoregraphics(W); }