Annotation of OpenXM_contrib/pari-2.2/src/graph/plotport.c, Revision 1.1.1.1
1.1 noro 1: /* $Id: plotport.c,v 1.15 2001/03/26 13:52:07 karim Exp $
2:
3: Copyright (C) 2000 The PARI group.
4:
5: This file is part of the PARI/GP package.
6:
7: PARI/GP is free software; you can redistribute it and/or modify it under the
8: terms of the GNU General Public License as published by the Free Software
9: Foundation. It is distributed in the hope that it will be useful, but WITHOUT
10: ANY WARRANTY WHATSOEVER.
11:
12: Check the License for details. You should have received a copy of it, along
13: with the package; see the file 'COPYING'. If not, write to the Free Software
14: Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
15:
16: /*******************************************************************/
17: /* */
18: /* PLOT ROUTINES */
19: /* */
20: /*******************************************************************/
21: #include "pari.h"
22: #include "rect.h"
23:
24: extern void push_val(entree *ep, GEN a);
25: extern void pop_val(entree *ep);
26: extern void postdraw0(long *w, long *x, long *y, long lw);
27: extern void postdraw00(long *w, long *x, long *y, long lw, long scale);
28: extern void rectdraw0(long *w, long *x, long *y, long lw, long do_free);
29: static void PARI_get_psplot();
30:
31: static long current_color[NUMRECT];
32: PariRect **rectgraph = NULL;
33: PARI_plot pari_plot, pari_psplot;
34: long rectpoint_itype = 0;
35: long rectline_itype = 0;
36:
37: #define STRINGRECT (NUMRECT-2)
38: #define DRAWRECT (NUMRECT-1)
39:
40: #define PLOTH_NUMPOINTS 1000
41: #define PARAM_NUMPOINTS 1500
42: #define RECUR_NUMPOINTS 8
43:
44: #define RECUR_MAXDEPTH 10
45: #define RECUR_PREC 0.001
46: #define PARAMR_MAXDEPTH 10
47:
48: /********************************************************************/
49: /** **/
50: /** LOW-RES PLOT **/
51: /** **/
52: /********************************************************************/
53: #define ISCR 64
54: #define JSCR 22
55: #define BLANK ' '
56: #define ZERO1 ','
57: #define ZERO2 '-'
58: #define ZERO3 '`'
59: #define PICTZERO(j) ((j) % 3 ? ((j) % 3 == 2 ? ZERO3 : ZERO2) : ZERO1)
60: #define YY '|'
61: #define XX_UPPER '\''
62: #define XX_LOWER '.'
63: #define FF1 '_'
64: #define FF2 'x'
65: #define FF3 '"'
66: #define PICT(j) ((j) % 3 ? ((j) % 3 == 2 ? FF3 : FF2) : FF1)
67:
68: static char *
69: dsprintf9(double d, char *buf)
70: {
71: int i = 10;
72:
73: while (--i >= 0) {
74: sprintf(buf, "%9.*g", i, d);
75: if (strlen(buf) <= 9) return buf;
76: }
77: return buf; /* Should not happen? */
78: }
79:
80: typedef unsigned char screen[ISCR+1][JSCR+1];
81:
82: static void
83: fill_gap(screen scr, long i, int jnew, int jpre)
84: {
85: int mid, i_up, i_lo, up, lo;
86:
87: if (jpre < jnew - 2) {
88: up = jnew - 1; i_up = i;
89: lo = jpre + 1; i_lo = i - 1;
90: } else if (jnew < jpre - 2) {
91: up = jpre - 1; i_up = i - 1;
92: lo = jnew + 1; i_lo = i;
93: } else return; /* if gap < 2, leave it as it is. */
94:
95: mid = (jpre+jnew)/2;
96: if (mid>JSCR) mid=JSCR; else if (mid<0) mid=0;
97: if (lo<0) lo=0;
98: if (lo<=JSCR) while (lo <= mid) scr[i_lo][lo++] = ':';
99: if (up>JSCR) up=JSCR;
100: if (up>=0) while (up > mid) scr[i_up][up--] = ':';
101: }
102:
103: #define QUARK ((char*)NULL) /* Used as a special-case */
104: static GEN quark_gen;
105:
106: #define READ_EXPR(s) ((s)==QUARK? quark_gen : lisexpr(s))
107:
108: void
109: plot(entree *ep, GEN a, GEN b, char *ch,GEN ysmlu,GEN ybigu, long prec)
110: {
111: long av = avma, av2,limite,jz,j,i,sig;
112: int jnew, jpre = 0; /* for lint */
113: GEN p1,p2,ysml,ybig,x,diff,dyj,dx,y[ISCR+1];
114: screen scr;
115: char buf[80], z;
116:
117: sig=gcmp(b,a); if (!sig) return;
118: if (sig<0) { x=a; a=b; b=x; }
119: x = cgetr(prec); gaffect(a,x); push_val(ep, x);
120: for (i=1; i<=ISCR; i++) y[i]=cgetr(3);
121: p1 = gdivgs(gsub(b,a), ISCR-1);
122: dx = cgetr(prec); gaffect(p1, dx);
123: ysml=gzero; ybig=gzero;
124: for (j=1; j<=JSCR; j++) scr[1][j]=scr[ISCR][j]=YY;
125: for (i=2; i<ISCR; i++)
126: {
127: scr[i][1] = XX_LOWER;
128: scr[i][JSCR]=XX_UPPER;
129: for (j=2; j<JSCR; j++) scr[i][j]=BLANK;
130: }
131: av2=avma; limite=stack_lim(av2,1);
132: for (i=1; i<=ISCR; i++)
133: {
134: gaffect(READ_EXPR(ch),y[i]);
135: if (gcmp(y[i],ysml)<0) ysml=y[i];
136: if (gcmp(y[i],ybig)>0) ybig=y[i];
137: x = addrr(x,dx);
138: if (low_stack(limite, stack_lim(av2,1)))
139: {
140: long tetpil=avma;
141: if (DEBUGMEM>1) err(warnmem,"plot");
142: x = gerepile(av2,tetpil,rcopy(x));
143: }
144: ep->value = (void*)x;
145: }
146: if (ysmlu) ysml=ysmlu;
147: if (ybigu) ybig=ybigu;
148: avma=av2; diff=gsub(ybig,ysml);
149: if (gcmp0(diff)) { ybig=gaddsg(1,ybig); diff=gun; }
150: dyj = gdivsg((JSCR-1)*3+2,diff);
151: jz = 3-gtolong(gmul(ysml,dyj));
152: av2=avma; z = PICTZERO(jz); jz = jz/3;
153: for (i=1; i<=ISCR; i++)
154: {
155: if (0<=jz && jz<=JSCR) scr[i][jz]=z;
156: j = 3+gtolong(gmul(gsub(y[i],ysml),dyj));
157: jnew = j/3;
158: if (i > 1) fill_gap(scr, i, jnew, jpre);
159: if (0<=jnew && jnew<=JSCR) scr[i][jnew] = PICT(j);
160: avma = av2;
161: jpre = jnew;
162: }
163: p1=cgetr(3); gaffect(ybig,p1); pariputc('\n');
164: pariputsf("%s ", dsprintf9(rtodbl(p1), buf));
165: for (i=1; i<=ISCR; i++) pariputc(scr[i][JSCR]);
166: pariputc('\n');
167: for (j=(JSCR-1); j>=2; j--)
168: {
169: pariputs(" ");
170: for (i=1; i<=ISCR; i++) pariputc(scr[i][j]);
171: pariputc('\n');
172: }
173: p1=cgetr(3); gaffect(ysml,p1);
174: pariputsf("%s ", dsprintf9(rtodbl(p1), buf));
175: for (i=1; i<=ISCR; i++) pariputc(scr[i][1]);
176: pariputc('\n');
177: p1=cgetr(3); gaffect(a,p1);
178: p2=cgetr(3); gaffect(b,p2);
179: pariputsf("%10s%-9.7g%*.7g\n"," ",rtodbl(p1),ISCR-9,rtodbl(p2));
180: pop_val(ep); avma=av;
181: }
182:
183: /********************************************************************/
184: /** **/
185: /** RECTPLOT FUNCTIONS **/
186: /** **/
187: /********************************************************************/
188: void
189: init_graph()
190: {
191: int n;
192:
193: rectgraph = (PariRect**) gpmalloc(sizeof(PariRect*)*NUMRECT);
194: for (n=0; n<NUMRECT; n++)
195: {
196: PariRect *e = (PariRect*) gpmalloc(sizeof(PariRect));
197:
198: e->head = e->tail = NULL;
199: e->sizex = e->sizey = 0;
200: current_color[n] = DEFAULT_COLOR;
201: rectgraph[n] = e;
202: }
203: }
204:
205: void
206: free_graph()
207: {
208: int i;
209:
210: for (i=0; i<NUMRECT; i++)
211: {
212: PariRect *e=rectgraph[i];
213:
214: if (RHead(e)) killrect(i);
215: free((void *)e);
216: }
217: free((void *)rectgraph);
218: }
219:
220: static PariRect *
221: check_rect(long ne)
222: {
223: if (!GOODRECT(ne))
224: err(talker,"not an rplot vector type in graphic function");
225: return rectgraph[ne];
226: }
227:
228: static PariRect *
229: check_rect_init(long ne)
230: {
231: PariRect *e = check_rect(ne);
232: if (!RHead(e))
233: err(talker,"you must initialize the rectwindow first");
234: return e;
235: }
236:
237: void
238: initrect_gen(long ne, GEN x, GEN y, long flag)
239: {
240: long xi, yi;
241: if (flag) {
242: double xd = gtodouble(x), yd = gtodouble(y);
243:
244: PARI_get_plot(0);
245: xi = w_width - 1; yi = w_height - 1;
246: if (xd)
247: xi = (long)(xd*xi + 0.5);
248: if (yd)
249: yi = (long)(yd*yi + 0.5);
250: } else {
251: xi = itos(x); yi = itos(y);
252: if (!xi || !yi)
253: PARI_get_plot(0);
254: if (!xi)
255: xi = w_width - 1;
256: if (!yi)
257: yi = w_height - 1;
258: }
259: initrect(ne, xi, yi);
260: }
261:
262: void
263: initrect(long ne, long x, long y)
264: {
265: PariRect *e;
266: RectObj *z;
267:
268: if (x<=1 || y<=1) err(talker,"incorrect dimensions in initrect");
269: e = check_rect(ne); if (RHead(e)) killrect(ne);
270:
271: z = (RectObj*) gpmalloc(sizeof(RectObj));
272: RoNext(z) = NULL;
273: RoType(z) = ROt_NULL;
274: RHead(e)=RTail(e)=z;
275: RXsize(e)=x; RYsize(e)=y;
276: RXcursor(e)=0; RYcursor(e)=0;
277: RXscale(e)=1; RXshift(e)=0;
278: RYscale(e)=1; RYshift(e)=0;
279: RHasGraph(e) = 0;
280: }
281:
282: GEN
283: rectcursor(long ne)
284: {
285: PariRect *e = check_rect_init(ne);
286: GEN z=cgetg(3,t_VEC);
287:
288: z[1] = lstoi((long)RXcursor(e)); z[2] = lstoi((long)RYcursor(e));
289: return z;
290: }
291:
292: static void
293: rectscale0(long ne, double x1, double x2, double y1, double y2)
294: {
295: PariRect *e = check_rect_init(ne);
296: double p2,p3;
297:
298: p2 = RXshift(e) + RXscale(e) * RXcursor(e);
299: p3 = RYshift(e) + RYscale(e) * RYcursor(e);
300: RXscale(e) = RXsize(e)/(x2-x1); RXshift(e) = -x1*RXscale(e);
301: RYscale(e) = RYsize(e)/(y1-y2); RYshift(e) = -y2*RYscale(e);
302: RXcursor(e) = (p2 - RXshift(e)) / RXscale(e);
303: RYcursor(e) = (p3 - RYshift(e)) / RYscale(e);
304: }
305:
306: void
307: rectscale(long ne, GEN x1, GEN x2, GEN y1, GEN y2)
308: {
309: rectscale0(ne, gtodouble(x1), gtodouble(x2), gtodouble(y1), gtodouble(y2));
310: }
311:
312: /*
313: * #ifdef LONG_IS_64BIT
314: * # define MAXDTOL 9223372036854775807.0
315: * #else
316: * # define MAXDTOL 2147483647.0
317: * #endif
318: *
319: *
320: * long
321: * DTOL(double t)
322: * {
323: * if (fabs(t) > MAXDTOL) err(affer2);
324: * return (long)t;
325: * }
326: */
327:
328: static void
329: rectmove0(long ne, double x, double y, long relative)
330: {
331: PariRect *e = check_rect_init(ne);
332: RectObj *z = (RectObj*) gpmalloc(sizeof(RectObj1P));
333:
334: if (relative)
335: { RXcursor(e) += x; RYcursor(e) += y; }
336: else
337: { RXcursor(e) = x; RYcursor(e) = y; }
338: RoNext(z) = 0; RoType(z) = ROt_MV;
339: RoMVx(z) = RXcursor(e) * RXscale(e) + RXshift(e);
340: RoMVy(z) = RYcursor(e) * RYscale(e) + RYshift(e);
341: if (!RHead(e)) RHead(e)=RTail(e)=z;
342: else { RoNext(RTail(e))=z; RTail(e)=z; }
343: }
344:
345: void
346: rectmove(long ne, GEN x, GEN y)
347: {
348: rectmove0(ne,gtodouble(x),gtodouble(y),0);
349: }
350:
351: void
352: rectrmove(long ne, GEN x, GEN y)
353: {
354: rectmove0(ne,gtodouble(x),gtodouble(y),1);
355: }
356:
357: void
358: rectpoint0(long ne, double x, double y,long relative) /* code = ROt_MV/ROt_PT */
359: {
360: PariRect *e = check_rect_init(ne);
361: RectObj *z = (RectObj*) gpmalloc(sizeof(RectObj1P));
362:
363: if (relative)
364: { RXcursor(e) += x; RYcursor(e) += y; }
365: else
366: { RXcursor(e) = x; RYcursor(e) = y; }
367: RoNext(z)=0;
368: RoPTx(z) = RXcursor(e)*RXscale(e) + RXshift(e);
369: RoPTy(z) = RYcursor(e)*RYscale(e) + RYshift(e);
370: RoType(z) = ( DTOL(RoPTx(z)) < 0
371: || DTOL(RoPTy(z)) < 0 || DTOL(RoPTx(z)) > RXsize(e)
372: || DTOL(RoPTy(z)) > RYsize(e) ) ? ROt_MV : ROt_PT;
373: if (!RHead(e)) RHead(e)=RTail(e)=z;
374: else { RoNext(RTail(e))=z; RTail(e)=z; }
375: RoCol(z)=current_color[ne];
376: }
377:
378: void
379: rectpoint(long ne, GEN x, GEN y)
380: {
381: rectpoint0(ne,gtodouble(x),gtodouble(y),0);
382: }
383:
384: void
385: rectrpoint(long ne, GEN x, GEN y)
386: {
387: rectpoint0(ne,gtodouble(x),gtodouble(y),1);
388: }
389:
390: void
391: rectcolor(long ne, long color)
392: {
393: check_rect(ne);
394: if (!GOODCOLOR(color)) err(talker,"This is not a valid color");
395: current_color[ne]=color;
396: }
397:
398: void
399: rectline0(long ne, double gx2, double gy2, long relative) /* code = ROt_MV/ROt_LN */
400: {
401: double dx,dy,dxy,xmin,xmax,ymin,ymax,x1,y1,x2,y2;
402: PariRect *e = check_rect_init(ne);
403: RectObj *z = (RectObj*) gpmalloc(sizeof(RectObj2P));
404: const double c = 1 + 1e-10;
405:
406: x1 = RXcursor(e)*RXscale(e) + RXshift(e);
407: y1 = RYcursor(e)*RYscale(e) + RYshift(e);
408: if (relative)
409: { RXcursor(e)+=gx2; RYcursor(e)+=gy2; }
410: else
411: { RXcursor(e)=gx2; RYcursor(e)=gy2; }
412: x2 = RXcursor(e)*RXscale(e) + RXshift(e);
413: y2 = RYcursor(e)*RYscale(e) + RYshift(e);
414: xmin = max(min(x1,x2),0); xmax = min(max(x1,x2),RXsize(e));
415: ymin = max(min(y1,y2),0); ymax = min(max(y1,y2),RYsize(e));
416: dxy = x1*y2 - y1*x2; dx = x2-x1; dy = y2-y1;
417: if (dy)
418: {
419: if (dx*dy<0)
420: { xmin = max(xmin,(dxy+RYsize(e)*dx)/dy); xmax=min(xmax,dxy/dy); }
421: else
422: { xmin=max(xmin,dxy/dy); xmax=min(xmax,(dxy+RYsize(e)*dx)/dy); }
423: }
424: if (dx)
425: {
426: if (dx*dy<0)
427: { ymin=max(ymin,(RXsize(e)*dy-dxy)/dx); ymax=min(ymax,-dxy/dx); }
428: else
429: { ymin=max(ymin,-dxy/dx); ymax=min(ymax,(RXsize(e)*dy-dxy)/dx); }
430: }
431: RoNext(z)=0;
432: RoLNx1(z) = xmin; RoLNx2(z) = xmax;
433: if (dx*dy<0) { RoLNy1(z) = ymax; RoLNy2(z) = ymin; }
434: else { RoLNy1(z) = ymin; RoLNy2(z) = ymax; }
435: RoType(z) = (xmin>xmax*c || ymin>ymax*c) ? ROt_MV : ROt_LN;
436: if (!RHead(e)) RHead(e)=RTail(e)=z;
437: else { RoNext(RTail(e))=z; RTail(e)=z; }
438: RoCol(z)=current_color[ne];
439: }
440:
441: /* Given coordinates of ends of a line, and labels l1 l2 attached to the
442: ends, plot ticks where the label coordinate takes "round" values */
443:
444: static void
445: rectticks(PARI_plot *WW, long ne,
446: double dx1, double dy1, double dx2, double dy2,
447: double l1, double l2, long flags)
448: {
449: long dx,dy,dxy,dxy1,x1,y1,x2,y2,nticks,n,n1,dn;
450: double minstep, maxstep, step, l_min, l_max, minl, maxl, dl, dtx, dty, x, y;
451: double ddx, ddy;
452: const double mult[3] = { 2./1., 5./2., 10./5. };
453: PariRect *e = check_rect_init(ne);
454: int do_double = !(flags & TICKS_NODOUBLE);
455:
456: x1 = DTOL(dx1*RXscale(e) + RXshift(e));
457: y1 = DTOL(dy1*RYscale(e) + RYshift(e));
458: x2 = DTOL(dx2*RXscale(e) + RXshift(e));
459: y2 = DTOL(dy2*RYscale(e) + RYshift(e));
460: dx = x2 - x1;
461: dy = y2 - y1;
462: if (dx < 0) dx = -dx;
463: if (dy < 0) dy = -dy;
464: dxy1 = max(dx, dy);
465: if (WW) {
466: dx /= WW->hunit;
467: dy /= WW->vunit;
468: }
469: else {
470: PARI_get_plot(0);
471: dx /= h_unit;
472: dy /= v_unit;
473: }
474: dxy = (long)sqrt(dx*dx + dy*dy);
475: nticks = (long) ((dxy + 2.5)/4);
476: if (!nticks) return;
477:
478: /* Now we want to find nticks (or less) "round" numbers between l1 and l2.
479: For our purpose round numbers have "last significant" digit either
480: *) any;
481: *) even;
482: *) divisible by 5.
483: We need to choose which alternative is better.
484: */
485: if (l1 < l2)
486: l_min = l1, l_max = l2;
487: else
488: l_min = l2, l_max = l1;
489: minstep = (l_max - l_min)/(nticks + 1);
490: maxstep = 2.5*(l_max - l_min);
491: step = exp(log(10) * floor(log10(minstep)));
492: if (!(flags & TICKS_ENDSTOO)) {
493: double d = 2*(l_max - l_min)/dxy1; /* Two pixels off */
494:
495: l_min += d;
496: l_max -= d;
497: }
498: for (n = 0; ; n++) {
499: if (step >= maxstep) return;
500:
501: if (step >= minstep) {
502: minl = ceil(l_min/step);
503: maxl = floor(l_max/step);
504: if (minl <= maxl && maxl - minl + 1 <= nticks) {
505: nticks = (long) (maxl - minl + 1);
506: l_min = minl * step;
507: l_max = maxl * step; break;
508: }
509: }
510: step *= mult[ n % 3 ];
511: }
512: /* Where to position doubleticks, variants:
513: small: each 5, double: each 10 (n===2 mod 3)
514: small: each 2, double: each 10 (n===1 mod 3)
515: small: each 1, double: each 5 */
516: dn = (n % 3 == 2)? 2: 5;
517: n1 = ((long)minl) % dn; /* unused if do_double = FALSE */
518:
519: /* now l_min and l_max keep min/max values of l with ticks, and nticks is
520: the number of ticks to draw. */
521: if (nticks == 1) ddx = ddy = 0; /* unused: for lint */
522: else {
523: dl = (l_max - l_min)/(nticks - 1);
524: ddx = (dx2 - dx1) * dl / (l2 - l1);
525: ddy = (dy2 - dy1) * dl / (l2 - l1);
526: }
527: x = dx1 + (dx2 - dx1) * (l_min - l1) / (l2 - l1);
528: y = dy1 + (dy2 - dy1) * (l_min - l1) / (l2 - l1);
529: /* assume h_unit and v_unit form a square. For clockwise ticks: */
530: dtx = h_unit * dy/dxy * (y2 > y1 ? 1 : -1); /* y-coord runs down */
531: dty = v_unit * dx/dxy * (x2 > x1 ? 1 : -1);
532: for (n = 0; n < nticks; n++) {
533: RectObj *z = (RectObj*) gpmalloc(sizeof(RectObj2P));
534: double lunit = h_unit > 1 ? 1.5 : 2;
535: double l = (do_double && (n + n1) % dn == 0) ? lunit: 1;
536:
537: RoNext(z) = 0;
538: RoLNx1(z) = RoLNx2(z) = x*RXscale(e) + RXshift(e);
539: RoLNy1(z) = RoLNy2(z) = y*RYscale(e) + RYshift(e);
540:
541: if (flags & TICKS_CLOCKW) {
542: RoLNx1(z) += dtx*l;
543: RoLNy1(z) -= dty*l; /* y-coord runs down */
544: }
545: if (flags & TICKS_ACLOCKW) {
546: RoLNx2(z) -= dtx*l;
547: RoLNy2(z) += dty*l; /* y-coord runs down */
548: }
549: RoType(z) = ROt_LN;
550:
551: if (!RHead(e))
552: RHead(e)=RTail(e)=z;
553: else {
554: RoNext(RTail(e))=z; RTail(e)=z;
555: }
556: RoCol(z)=current_color[ne];
557: x += ddx;
558: y += ddy;
559: }
560: }
561:
562: void
563: rectline(long ne, GEN gx2, GEN gy2)
564: {
565: rectline0(ne, gtodouble(gx2), gtodouble(gy2),0);
566: }
567:
568: void
569: rectrline(long ne, GEN gx2, GEN gy2)
570: {
571: rectline0(ne, gtodouble(gx2), gtodouble(gy2),1);
572: }
573:
574: void
575: rectbox0(long ne, double gx2, double gy2, long relative)
576: {
577: double x1,y1,x2,y2,xmin,ymin,xmax,ymax;
578: double xx,yy;
579: PariRect *e = check_rect_init(ne);
580: RectObj *z = (RectObj*) gpmalloc(sizeof(RectObj2P));
581:
582: x1 = RXcursor(e)*RXscale(e) + RXshift(e);
583: y1 = RYcursor(e)*RYscale(e) + RYshift(e);
584: if (relative)
585: { xx = RXcursor(e)+gx2; yy = RYcursor(e)+gy2; }
586: else
587: { xx = gx2; yy = gy2; }
588: x2 = xx*RXscale(e) + RXshift(e);
589: y2 = yy*RYscale(e) + RYshift(e);
590: xmin = max(min(x1,x2),0); xmax = min(max(x1,x2),RXsize(e));
591: ymin = max(min(y1,y2),0); ymax = min(max(y1,y2),RYsize(e));
592:
593: RoNext(z)=0; RoType(z) = ROt_BX;
594: RoBXx1(z) = xmin; RoBXy1(z) = ymin;
595: RoBXx2(z) = xmax; RoBXy2(z) = ymax;
596: if (!RHead(e)) RHead(e)=RTail(e)=z;
597: else { RoNext(RTail(e))=z; RTail(e)=z; }
598: RoCol(z)=current_color[ne];
599: }
600:
601: void
602: rectbox(long ne, GEN gx2, GEN gy2)
603: {
604: rectbox0(ne, gtodouble(gx2), gtodouble(gy2), 0);
605: }
606:
607: void
608: rectrbox(long ne, GEN gx2, GEN gy2)
609: {
610: rectbox0(ne, gtodouble(gx2), gtodouble(gy2), 1);
611: }
612:
613: void
614: killrect(long ne)
615: {
616: RectObj *p1,*p2;
617: PariRect *e = check_rect_init(ne);
618:
619: current_color[ne]=DEFAULT_COLOR;
620: p1=RHead(e);
621: RHead(e) = RTail(e) = NULL;
622: RXsize(e) = RYsize(e) = 0;
623: RXcursor(e) = RYcursor(e) = 0;
624: RXscale(e) = RYscale(e) = 1;
625: RXshift(e) = RYshift(e) = 0;
626: while (p1)
627: {
628: if (RoType(p1)==ROt_MP || RoType(p1)==ROt_ML)
629: {
630: free(RoMPxs(p1)); free(RoMPys(p1));
631: }
632: if (RoType(p1)==ROt_ST) free(RoSTs(p1));
633: p2=RoNext(p1); free(p1); p1=p2;
634: }
635: }
636:
637: void
638: rectpoints0(long ne, double *listx, double *listy, long lx) /* code = ROt_MP */
639: {
640: double *ptx, *pty, x, y;
641: long i, cp=0;
642: PariRect *e = check_rect_init(ne);
643: RectObj *z = (RectObj*) gpmalloc(sizeof(RectObjMP));
644:
645: ptx=(double*) gpmalloc(lx*sizeof(double));
646: pty=(double*) gpmalloc(lx*sizeof(double));
647: for (i=0; i<lx; i++)
648: {
649: x = RXscale(e)*listx[i] + RXshift(e);
650: y = RYscale(e)*listy[i] + RYshift(e);
651: if ((x>=0)&&(y>=0)&&(x<=RXsize(e))&&(y<=RYsize(e)))
652: {
653: ptx[cp]=x; pty[cp]=y; cp++;
654: }
655: }
656: RoNext(z)=0; RoType(z) = ROt_MP;
657: RoMPcnt(z) = cp; RoMPxs(z) = ptx; RoMPys(z) = pty;
658: if (!RHead(e)) RHead(e)=RTail(e)=z;
659: else { RoNext(RTail(e))=z; RTail(e)=z; }
660: RoCol(z)=current_color[ne];
661: }
662:
663: void
664: rectpoints(long ne, GEN listx, GEN listy)
665: {
666: long i,lx, tx=typ(listx), ty=typ(listy);
667: double *px,*py;
668:
669: if (!is_matvec_t(tx) || !is_matvec_t(ty))
670: {
671: rectpoint(ne, listx, listy); return;
672: }
673: if (tx == t_MAT || ty == t_MAT) err(ploter4);
674: lx=lg(listx); if (lg(listy)!=lx) err(ploter5);
675: lx--; if (!lx) return;
676:
677: px = (double*) gpmalloc(lx*sizeof(double));
678: py = (double*) gpmalloc(lx*sizeof(double));
679: for (i=0; i<lx; i++)
680: {
681: px[i]=gtodouble((GEN)listx[i+1]); py[i]=gtodouble((GEN)listy[i+1]);
682: }
683: rectpoints0(ne,px,py,lx);
684: free(px); free(py);
685: }
686:
687: void
688: rectlines0(long ne, double *x, double *y, long lx, long flag) /* code = ROt_ML */
689: {
690: long i,I;
691: double *ptx,*pty;
692: PariRect *e = check_rect_init(ne);
693: RectObj *z = (RectObj*) gpmalloc(sizeof(RectObj2P));
694:
695: I = flag ? lx+1 : lx;
696: ptx = (double*) gpmalloc(I*sizeof(double));
697: pty = (double*) gpmalloc(I*sizeof(double));
698: for (i=0; i<lx; i++)
699: {
700: ptx[i] = RXscale(e)*x[i] + RXshift(e);
701: pty[i] = RYscale(e)*y[i] + RYshift(e);
702: }
703: if (flag)
704: {
705: ptx[i] = RXscale(e)*x[0] + RXshift(e);
706: pty[i] = RYscale(e)*y[0] + RYshift(e);
707: }
708: RoNext(z)=0; RoType(z)=ROt_ML;
709: RoMLcnt(z)=lx; RoMLxs(z)=ptx; RoMLys(z)=pty;
710: if (!RHead(e)) RHead(e)=RTail(e)=z;
711: else { RoNext(RTail(e))=z; RTail(e)=z; }
712: RoCol(z) = current_color[ne];
713: }
714:
715: void
716: rectlines(long ne, GEN listx, GEN listy, long flag)
717: {
718: long tx=typ(listx), ty=typ(listy), lx=lg(listx), i;
719: double *x, *y;
720:
721: if (!is_matvec_t(tx) || !is_matvec_t(ty))
722: {
723: rectline(ne, listx, listy); return;
724: }
725: if (tx == t_MAT || ty == t_MAT) err(ploter4);
726: if (lg(listy)!=lx) err(ploter5);
727: lx--; if (!lx) return;
728:
729: x = (double*) gpmalloc(lx*sizeof(double));
730: y = (double*) gpmalloc(lx*sizeof(double));
731: for (i=0; i<lx; i++)
732: {
733: x[i] = gtodouble((GEN)listx[i+1]); y[i] = gtodouble((GEN)listy[i+1]);
734: }
735: rectlines0(ne,x,y,lx,flag);
736: free(x); free(y);
737: }
738:
739: static void
740: put_string(long win, long x, long y, char *str, long dir)
741: {
742: rectmove0(win,(double)x,(double)y,0); rectstring3(win,str,dir);
743: }
744:
745: void
746: rectstring(long ne, char *str)
747: {
748: rectstring3(ne,str,RoSTdirLEFT);
749: }
750:
751: /* Allocate memory, then put string */
752: void
753: rectstring3(long ne, char *str, long dir) /* code = ROt_ST */
754: {
755: PariRect *e = check_rect_init(ne);
756: RectObj *z = (RectObj*) gpmalloc(sizeof(RectObjST));
757: long l = strlen(str);
758: char *s = (char *) gpmalloc(l+1);
759:
760: strcpy(s,str);
761: RoNext(z)=0; RoType(z) = ROt_ST;
762: RoSTl(z) = l; RoSTs(z) = s;
763: RoSTx(z) = RXscale(e)*RXcursor(e)+RXshift(e);
764: RoSTy(z) = RYscale(e)*RYcursor(e)+RYshift(e);
765: RoSTdir(z) = dir;
766: if (!RHead(e)) RHead(e)=RTail(e)=z;
767: else { RoNext(RTail(e))=z; RTail(e)=z; }
768: RoCol(z)=current_color[ne];
769: }
770:
771: void
772: rectpointtype(long ne, long type) /* code = ROt_PTT */
773: {
774: if (ne == -1) {
775: rectpoint_itype = type;
776: } else {
777: PariRect *e = check_rect_init(ne);
778: RectObj *z = (RectObj*) gpmalloc(sizeof(RectObjPN));
779:
780: RoNext(z) = 0; RoType(z) = ROt_PTT;
781: RoPTTpen(z) = type;
782: if (!RHead(e)) RHead(e)=RTail(e)=z;
783: else { RoNext(RTail(e))=z; RTail(e)=z; }
784: }
785: }
786:
787: void
788: rectpointsize(long ne, GEN size) /* code = ROt_PTS */
789: {
790: if (ne == -1) {
791: set_pointsize(gtodouble(size)); /* Immediate set */
792: } else {
793: PariRect *e = check_rect_init(ne);
794: RectObj *z = (RectObj*) gpmalloc(sizeof(RectObjPS));
795:
796: RoNext(z) = 0; RoType(z) = ROt_PTS;
797: RoPTSsize(z) = gtodouble(size);
798: if (!RHead(e)) RHead(e)=RTail(e)=z;
799: else { RoNext(RTail(e))=z; RTail(e)=z; }
800: }
801: }
802:
803: void
804: rectlinetype(long ne, long type)
805: {
806: if (ne == -1) {
807: rectline_itype = type;
808: } else {
809: PariRect *e = check_rect_init(ne);
810: RectObj *z = (RectObj*) gpmalloc(sizeof(RectObjPN));
811:
812: RoNext(z) = 0; RoType(z) = ROt_LNT;
813: RoLNTpen(z) = type;
814: if (!RHead(e)) RHead(e)=RTail(e)=z;
815: else { RoNext(RTail(e))=z; RTail(e)=z; }
816: }
817: }
818:
819: void
820: rectcopy_gen(long source, long dest, GEN xoff, GEN yoff, long flag)
821: {
822: long xi, yi;
823: if (flag & RECT_CP_RELATIVE) {
824: double xd = gtodouble(xoff), yd = gtodouble(yoff);
825:
826: PARI_get_plot(0);
827: xi = w_width - 1; yi = w_height - 1;
828: xi = (long)(xd*xi + 0.5);
829: yi = (long)(yd*yi + 0.5);
830: } else {
831: xi = itos(xoff); yi = itos(yoff);
832: }
833: if (flag & ~RECT_CP_RELATIVE) {
834: PariRect *s = check_rect_init(source), *d = check_rect_init(dest);
835:
836: switch (flag & ~RECT_CP_RELATIVE) {
837: case RECT_CP_NW:
838: break;
839: case RECT_CP_SW:
840: yi = RYsize(d) - RYsize(s) - yi;
841: break;
842: case RECT_CP_SE:
843: yi = RYsize(d) - RYsize(s) - yi;
844: /* FALL THROUGH */
845: case RECT_CP_NE:
846: xi = RXsize(d) - RXsize(s) - xi;
847: break;
848: }
849: }
850: rectcopy(source, dest, xi, yi);
851: }
852:
853: void
854: rectcopy(long source, long dest, long xoff, long yoff)
855: {
856: PariRect *s = check_rect_init(source), *d = check_rect_init(dest);
857: RectObj *p1 = RHead(s);
858: RectObj *tail = RTail(d);
859: RectObj *next;
860: int i;
861:
862: while (p1)
863: {
864: switch(RoType(p1))
865: {
866: case ROt_PT:
867: next = (RectObj*) gpmalloc(sizeof(RectObj1P));
868: memcpy(next,p1,sizeof(RectObj1P));
869: RoPTx(next) += xoff; RoPTy(next) += yoff;
870: RoNext(tail) = next; tail = next;
871: break;
872: case ROt_LN: case ROt_BX:
873: next = (RectObj*) gpmalloc(sizeof(RectObj2P));
874: memcpy(next,p1,sizeof(RectObj2P));
875: RoLNx1(next) += xoff; RoLNy1(next) += yoff;
876: RoLNx2(next) += xoff; RoLNy2(next) += yoff;
877: RoNext(tail) = next; tail = next;
878: break;
879: case ROt_MP: case ROt_ML:
880: next = (RectObj*) gpmalloc(sizeof(RectObjMP));
881: memcpy(next,p1,sizeof(RectObjMP));
882: RoMPxs(next) = (double*) gpmalloc(sizeof(double)*RoMPcnt(next));
883: RoMPys(next) = (double*) gpmalloc(sizeof(double)*RoMPcnt(next));
884: memcpy(RoMPxs(next),RoMPxs(p1),sizeof(double)*RoMPcnt(next));
885: memcpy(RoMPys(next),RoMPys(p1),sizeof(double)*RoMPcnt(next));
886: for (i=0; i<RoMPcnt(next); i++)
887: {
888: RoMPxs(next)[i] += xoff; RoMPys(next)[i] += yoff;
889: }
890: RoNext(tail) = next; tail = next;
891: break;
892: case ROt_ST:
893: next = (RectObj*) gpmalloc(sizeof(RectObjST));
894: memcpy(next,p1,sizeof(RectObjMP));
895: RoSTs(next) = (char*) gpmalloc(RoSTl(p1)+1);
896: memcpy(RoSTs(next),RoSTs(p1),RoSTl(p1)+1);
897: RoSTx(next) += xoff; RoSTy(next) += yoff;
898: RoNext(tail) = next; tail = next;
899: break;
900: case ROt_PTT: case ROt_LNT: case ROt_PTS:
901: next = (RectObj*) gpmalloc(sizeof(RectObjPN));
902: memcpy(next,p1,sizeof(RectObjPN));
903: RoNext(tail) = next; tail = next;
904: break;
905: }
906: p1=RoNext(p1);
907: }
908: RoNext(tail) = NULL; RTail(d) = tail;
909: }
910:
911: #define CLIPLINE_NONEMPTY 1
912: #define CLIPLINE_CLIP_1 2
913: #define CLIPLINE_CLIP_2 4
914:
915: /* A simpler way is to clip by 4 half-planes */
916: static int
917: clipline(double xmin, double xmax, double ymin, double ymax,
918: double *x1p, double *y1p, double *x2p, double *y2p)
919: {
920: int xy_exch = 0, rc = CLIPLINE_NONEMPTY;
921: double t, sl;
922: double xi, xmn, xmx;
923: double yi, ymn, ymx;
924: int x1_is_ymn, x1_is_xmn;
925: double x1 = *x1p, x2 = *x2p, y1 = *y1p, y2 = *y2p;
926:
927: if ((x1 < xmin && x2 < xmin) || (x1 > xmax && x2 > xmax))
928: return 0;
929: if (fabs(x1 - x2) < fabs(y1 - y2)) { /* Exchange x and y */
930: xy_exch = 1;
931: t = xmin; xmin = ymin; ymin = t;
932: t = xmax; xmax = ymax; ymax = t;
933: t = x1; x1 = y1; y1 = t;
934: t = x2; x2 = y2; y2 = t;
935: }
936:
937: /* Build y as a function of x */
938: xi = x1, yi = y1;
939: sl = ( (x1==x2) ? 0 : (y2 - yi)/(x2 - xi) );
940:
941: xmn = x1, xmx = x2;
942: if (x1 > x2) {
943: x1_is_xmn = 0;
944: xmn = x2, xmx = x1;
945: } else
946: x1_is_xmn = 1;
947:
948: if (xmn < xmin) {
949: xmn = xmin;
950: rc |= (x1_is_xmn ? CLIPLINE_CLIP_1 : CLIPLINE_CLIP_2);
951: }
952:
953: if (xmx > xmax) {
954: xmx = xmax;
955: rc |= (x1_is_xmn ? CLIPLINE_CLIP_2 : CLIPLINE_CLIP_1);
956: }
957:
958: if (xmn > xmx)
959: return 0;
960:
961: ymn = yi + (xmn - xi)*sl;
962: ymx = yi + (xmx - xi)*sl;
963:
964: if (sl < 0)
965: t = ymn, ymn = ymx, ymx = t;
966: if (ymn > ymax || ymx < ymin)
967: return 0;
968:
969: if (rc & CLIPLINE_CLIP_1)
970: x1 = (x1_is_xmn ? xmn : xmx);
971: if (rc & CLIPLINE_CLIP_2)
972: x2 = (x1_is_xmn ? xmx : xmn);
973:
974: /* Now we know there is an intersection, need to move x1 and x2 */
975: x1_is_ymn = ((sl >= 0) == (x1 < x2));
976: if (ymn < ymin) {
977: double x = (ymin - yi)/sl + xi; /* slope != 0 ! */
978:
979: if (x1_is_ymn)
980: x1 = x, rc |= CLIPLINE_CLIP_1;
981: else
982: x2 = x, rc |= CLIPLINE_CLIP_2;
983: }
984: if (ymx > ymax) {
985: double x = (ymax - yi)/sl + xi; /* slope != 0 ! */
986:
987: if (x1_is_ymn)
988: x2 = x, rc |= CLIPLINE_CLIP_2;
989: else
990: x1 = x, rc |= CLIPLINE_CLIP_1;
991: }
992: if (rc & CLIPLINE_CLIP_1)
993: y1 = yi + (x1 - xi)*sl;
994: if (rc & CLIPLINE_CLIP_2)
995: y2 = yi + (x2 - xi)*sl;
996: if (xy_exch) /* Exchange x and y */
997: *x1p = y1, *x2p = y2, *y1p = x1, *y2p = x2;
998: else
999: *x1p = x1, *x2p = x2, *y1p = y1, *y2p = y2;
1000: return rc;
1001: }
1002:
1003: void
1004: rectclip(long rect)
1005: {
1006: PariRect *s = check_rect_init(rect);
1007: RectObj *p1 = RHead(s);
1008: RectObj **prevp = &RHead(s);
1009: RectObj *next;
1010: double xmin = 0;
1011: double xmax = RXsize(s);
1012: double ymin = 0;
1013: double ymax = RYsize(s);
1014:
1015: while (p1) {
1016: int did_clip = 0;
1017:
1018: next = RoNext(p1);
1019: switch(RoType(p1)) {
1020: case ROt_PT:
1021: if ( DTOL(RoPTx(p1)) < xmin || DTOL(RoPTx(p1)) > xmax
1022: || DTOL(RoPTy(p1)) < ymin || DTOL(RoPTy(p1)) > ymax) {
1023: remove:
1024: *prevp = next;
1025: free(p1);
1026: break;
1027: }
1028: goto do_next;
1029: case ROt_BX:
1030: if (RoLNx1(p1) < xmin)
1031: RoLNx1(p1) = xmin, did_clip = 1;
1032: if (RoLNx2(p1) < xmin)
1033: RoLNx2(p1) = xmin, did_clip = 1;
1034: if (RoLNy1(p1) < ymin)
1035: RoLNy1(p1) = ymin, did_clip = 1;
1036: if (RoLNy2(p1) < ymin)
1037: RoLNy2(p1) = ymin, did_clip = 1;
1038: if (RoLNx1(p1) > xmax)
1039: RoLNx1(p1) = xmax, did_clip = 1;
1040: if (RoLNx2(p1) > xmax)
1041: RoLNx2(p1) = xmax, did_clip = 1;
1042: if (RoLNy1(p1) > ymax)
1043: RoLNy1(p1) = ymax, did_clip = 1;
1044: if (RoLNy2(p1) > ymax)
1045: RoLNy2(p1) = ymax, did_clip = 1;
1046: /* Remove zero-size clipped boxes */
1047: if ( did_clip
1048: && RoLNx1(p1) == RoLNx2(p1) && RoLNy1(p1) == RoLNy2(p1) )
1049: goto remove;
1050: goto do_next;
1051: case ROt_LN:
1052: if (!clipline(xmin, xmax, ymin, ymax,
1053: &RoLNx1(p1), &RoLNy1(p1), &RoLNx2(p1), &RoLNy2(p1)))
1054: goto remove;
1055: goto do_next;
1056: case ROt_MP:
1057: {
1058: int c = RoMPcnt(p1);
1059: int f = 0, t = 0;
1060:
1061: while (f < c) {
1062: if ( DTOL(RoMPxs(p1)[f]) >= xmin && DTOL(RoMPxs(p1)[f]) <= xmax
1063: && DTOL(RoMPys(p1)[f]) >= ymin
1064: && DTOL(RoMPys(p1)[f]) <= ymax) {
1065: if (t != f) {
1066: RoMPxs(p1)[t] = RoMPxs(p1)[f];
1067: RoMPys(p1)[t] = RoMPys(p1)[f];
1068: }
1069: t++;
1070: }
1071: f++;
1072: }
1073: if (t == 0)
1074: goto remove;
1075: RoMPcnt(p1) = t;
1076: goto do_next;
1077: }
1078: case ROt_ML:
1079: {
1080: /* Hard case. Here we need to break a multiline into
1081: several pieces if some part is clipped. */
1082: int c = RoMPcnt(p1) - 1;
1083: int f = 0, t = 0, had_lines = 0, had_hole = 0, rc;
1084: double ox = RoMLxs(p1)[0], oy = RoMLys(p1)[0], oxn, oyn;
1085:
1086: while (f < c) {
1087: /* Endpoint of this segment is the startpoint of the
1088: next one, so we need to preserve it if it is clipped. */
1089: oxn = RoMLxs(p1)[f + 1], oyn = RoMLys(p1)[f + 1];
1090: rc = clipline(xmin, xmax, ymin, ymax,
1091: /* &RoMLxs(p1)[f], &RoMLys(p1)[f], */
1092: &ox, &oy,
1093: &RoMLxs(p1)[f+1], &RoMLys(p1)[f+1]);
1094: RoMLxs(p1)[f] = ox; RoMLys(p1)[f] = oy;
1095: ox = oxn; oy = oyn;
1096: if (!rc) {
1097: if (had_lines)
1098: had_hole = 1;
1099: f++;
1100: continue;
1101: }
1102:
1103: if ( !had_lines || (!(rc & CLIPLINE_CLIP_1) && !had_hole) ) {
1104: /* Continuous */
1105: had_lines = 1;
1106: if (t != f) {
1107: if (t == 0) {
1108: RoMPxs(p1)[t] = RoMPxs(p1)[f];
1109: RoMPys(p1)[t] = RoMPys(p1)[f];
1110: }
1111: RoMPxs(p1)[t+1] = RoMPxs(p1)[f+1];
1112: RoMPys(p1)[t+1] = RoMPys(p1)[f+1];
1113: }
1114: t++;
1115: f++;
1116: if ( rc & CLIPLINE_CLIP_2)
1117: had_hole = 1, RoMLcnt(p1) = t + 1;
1118: continue;
1119: }
1120: /* Is not continuous, automatically p1 is not free()ed. */
1121: RoMLcnt(p1) = t + 1;
1122: if ( rc & CLIPLINE_CLIP_2) { /* Needs separate entry */
1123: RectObj *n = (RectObj*) gpmalloc(sizeof(RectObj2P));
1124:
1125: RoType(n) = ROt_LN;
1126: RoCol(n) = RoCol(p1);
1127: RoLNx1(n) = RoMLxs(p1)[f]; RoLNy1(n) = RoMLys(p1)[f];
1128: RoLNx2(n) = RoMLxs(p1)[f+1]; RoLNy2(n) = RoMLys(p1)[f+1];
1129: RoNext(n) = next;
1130: RoNext(p1) = n;
1131: /* Restore the unclipped value: */
1132: RoMLxs(p1)[f + 1] = oxn; RoMLys(p1)[f + 1] = oyn;
1133: f++;
1134: prevp = &RoNext(n);
1135: }
1136: if (f + 1 < c) { /* Are other lines */
1137: RectObj *n = (RectObj*) gpmalloc(sizeof(RectObjMP));
1138: RoType(n) = ROt_ML;
1139: RoCol(n) = RoCol(p1);
1140: RoMLcnt(n) = c - f;
1141: RoMLxs(n) = (double*) gpmalloc(sizeof(double)*(c - f));
1142: RoMLys(n) = (double*) gpmalloc(sizeof(double)*(c - f));
1143: memcpy(RoMPxs(n),RoMPxs(p1) + f, sizeof(double)*(c - f));
1144: memcpy(RoMPys(n),RoMPys(p1) + f, sizeof(double)*(c - f));
1145: RoMPxs(n)[0] = oxn; RoMPys(n)[0] = oyn;
1146: RoNext(n) = next;
1147: RoNext(p1) = n;
1148: next = n;
1149: }
1150: goto do_next;
1151: }
1152: if (t == 0)
1153: goto remove;
1154: goto do_next;
1155: }
1156: #if 0
1157: case ROt_ST:
1158: next = (RectObj*) gpmalloc(sizeof(RectObjMP));
1159: memcpy(next,p1,sizeof(RectObjMP));
1160: RoSTs(next) = (char*) gpmalloc(RoSTl(p1)+1);
1161: memcpy(RoSTs(next),RoSTs(p1),RoSTl(p1)+1);
1162: RoSTx(next) += xoff; RoSTy(next) += yoff;
1163: RoNext(tail) = next; tail = next;
1164: break;
1165: #endif
1166: default: {
1167: do_next:
1168: prevp = &RoNext(p1);
1169: break;
1170: }
1171: }
1172: p1 = next;
1173: }
1174: }
1175:
1176: /********************************************************************/
1177: /** **/
1178: /** HI-RES PLOT **/
1179: /** **/
1180: /********************************************************************/
1181:
1182: static void
1183: Appendx(dblPointList *f, dblPointList *l,double x)
1184: {
1185: (l->d)[l->nb++]=x;
1186: if (x < f->xsml) f->xsml=x;
1187: else if (x > f->xbig) f->xbig=x;
1188: }
1189:
1190: static void
1191: Appendy(dblPointList *f, dblPointList *l,double y)
1192: {
1193: (l->d)[l->nb++]=y;
1194: if (y < f->ysml) f->ysml=y;
1195: else if (y > f->ybig) f->ybig=y;
1196: }
1197:
1198: /* Convert data from GEN to double before we call rectplothrawin */
1199: static dblPointList*
1200: gtodblList(GEN data, long flags)
1201: {
1202: dblPointList *l;
1203: double xsml,xbig,ysml,ybig;
1204: long tx=typ(data), ty, nl=lg(data)-1, lx1,lx;
1205: register long i,j,u,v;
1206: long param=(flags & PLOT_PARAMETRIC);
1207: GEN x,y;
1208:
1209: if (! is_vec_t(tx)) err(talker,"not a vector in gtodblList");
1210: if (!nl) return NULL;
1211: lx1=lg(data[1]);
1212:
1213: /* Allocate memory, then convert coord. to double */
1214: l=(dblPointList*) gpmalloc(nl*sizeof(dblPointList));
1215: for (i=0; i<nl-1; i+=2)
1216: {
1217: u=i+1;
1218: x=(GEN)data[u]; tx = typ(x);
1219: y=(GEN)data[u+1]; ty = typ(y);
1220: if (!is_vec_t(tx) || !is_vec_t(ty)) err(ploter4);
1221: lx=lg(x); if (lg(y)!=lx) err(ploter5);
1222: if (!param && lx != lx1) err(ploter5);
1223: lx--;
1224:
1225: if (lx)
1226: {
1227: l[i].d = (double*) gpmalloc(lx*sizeof(double));
1228: l[u].d = (double*) gpmalloc(lx*sizeof(double));
1229:
1230: for (j=0; j<lx; j=v)
1231: {
1232: v=j+1;
1233: l[i].d[j]=gtodouble((GEN)x[v]);
1234: l[u].d[j]=gtodouble((GEN)y[v]);
1235: }
1236: }
1237: l[i].nb=l[u].nb=lx;
1238: }
1239:
1240: xsml=xbig=l[0].d[0]; ysml=ybig=l[1].d[0];
1241:
1242: /* Now compute extremas */
1243: if (param)
1244: {
1245: l[0].nb=nl/2;
1246: for (i=0; i<l[0].nb; i+=2)
1247: {
1248: u=i+1;
1249: for (j=0; j<l[u].nb; j++)
1250: {
1251: if (l[i].d[j]<xsml)
1252: xsml=l[i].d[j];
1253: else
1254: if (l[i].d[j]>xbig) xbig=l[i].d[j];
1255:
1256: if (l[u].d[j]<ysml)
1257: ysml=l[u].d[j];
1258: else
1259: if (l[u].d[j]>ybig) ybig=l[u].d[j];
1260: }
1261: }
1262: }
1263: else
1264: {
1265: l[0].nb=nl-1;
1266: for (j=0; j<l[1].nb; j++)
1267: {
1268: if (l[0].d[j]<xsml)
1269: xsml=l[0].d[j];
1270: else
1271: if (l[0].d[j]>xbig) xbig=l[0].d[j];
1272: }
1273: for (i=1; i<=l[0].nb; i++)
1274: {
1275: for (j=0; j<l[i].nb; j++)
1276: {
1277: if (l[i].d[j]<ysml)
1278: ysml=l[i].d[j];
1279: else
1280: if (l[i].d[j]>ybig) ybig=l[i].d[j];
1281: }
1282: }
1283: }
1284: l[0].xsml=xsml; l[0].xbig=xbig;
1285: l[0].ysml=ysml; l[0].ybig=ybig;
1286: return l;
1287: }
1288:
1289: static void
1290: single_recursion(dblPointList *pl,char *ch,entree *ep,GEN xleft,GEN yleft,
1291: GEN xright,GEN yright,long depth)
1292: {
1293: GEN xx,yy;
1294: long av=avma;
1295: double dy=pl[0].ybig - pl[0].ysml;
1296:
1297: if (depth==RECUR_MAXDEPTH) return;
1298:
1299: yy=cgetr(3); xx=gmul2n(gadd(xleft,xright),-1);
1300: ep->value = (void*) xx; gaffect(READ_EXPR(ch), yy);
1301:
1302: if (dy)
1303: {
1304: if (fabs(rtodbl(yleft)+rtodbl(yright)-2*rtodbl(yy))/dy < RECUR_PREC)
1305: return;
1306: }
1307: single_recursion(pl,ch,ep, xleft,yleft, xx,yy, depth+1);
1308:
1309: Appendx(&pl[0],&pl[0],rtodbl(xx));
1310: Appendy(&pl[0],&pl[1],rtodbl(yy));
1311:
1312: single_recursion(pl,ch,ep, xx,yy, xright,yright, depth+1);
1313:
1314: avma=av;
1315: }
1316:
1317: static void
1318: param_recursion(dblPointList *pl,char *ch,entree *ep, GEN tleft,GEN xleft,
1319: GEN yleft, GEN tright,GEN xright,GEN yright, long depth)
1320: {
1321: GEN tt,xx,yy, p1;
1322: long av=avma;
1323: double dy=pl[0].ybig - pl[0].ysml;
1324: double dx=pl[0].xbig - pl[0].xsml;
1325:
1326: if (depth==PARAMR_MAXDEPTH) return;
1327:
1328: xx=cgetr(3); yy=cgetr(3); tt=gmul2n(gadd(tleft,tright),-1);
1329: ep->value = (void*)tt; p1=READ_EXPR(ch);
1330: gaffect((GEN)p1[1],xx); gaffect((GEN)p1[2],yy);
1331:
1332: if (dx && dy)
1333: {
1334: if (fabs(rtodbl(xleft)+rtodbl(xright)-2*rtodbl(xx))/dx < RECUR_PREC &&
1335: fabs(rtodbl(yleft)+rtodbl(yright)-2*rtodbl(yy))/dy < RECUR_PREC)
1336: return;
1337: }
1338: param_recursion(pl,ch,ep, tleft,xleft,yleft, tt,xx,yy, depth+1);
1339:
1340: Appendx(&pl[0],&pl[0],rtodbl(xx));
1341: Appendy(&pl[0],&pl[1],rtodbl(yy));
1342:
1343: param_recursion(pl,ch,ep, tt,xx,yy, tright,xright,yright, depth+1);
1344:
1345: avma=av;
1346: }
1347:
1348: /*
1349: * Pure graphing. If testpoints is 0, it is set to the default.
1350: * Returns a dblPointList of (absolute) coordinates.
1351: */
1352: static dblPointList *
1353: rectplothin(entree *ep, GEN a, GEN b, char *ch, long prec, ulong flags,
1354: long testpoints)
1355: {
1356: long single_c;
1357: long param=flags & PLOT_PARAMETRIC;
1358: long recur=flags & PLOT_RECURSIVE;
1359: GEN p1,dx,x,xleft,xright,yleft,yright,tleft,tright;
1360: dblPointList *pl;
1361: long tx,av = avma,av2,i,j,sig,nc,nl,nbpoints;
1362: double xsml,xbig,ysml,ybig,fx,fy;
1363:
1364: if (!testpoints)
1365: {
1366: if (recur)
1367: testpoints = RECUR_NUMPOINTS;
1368: else
1369: testpoints = param? PARAM_NUMPOINTS : PLOTH_NUMPOINTS;
1370: }
1371: if (recur)
1372: nbpoints = testpoints << (param? PARAMR_MAXDEPTH : RECUR_MAXDEPTH);
1373: else
1374: nbpoints = testpoints;
1375:
1376: sig=gcmp(b,a); if (!sig) return 0;
1377: if (sig<0) { x=a; a=b; b=x; }
1378: dx=gdivgs(gsub(b,a),testpoints-1);
1379:
1380: x = cgetr(prec); gaffect(a,x); push_val(ep, x);
1381: av2=avma; p1=READ_EXPR(ch); tx=typ(p1);
1382: if (!is_matvec_t(tx))
1383: {
1384: xsml = gtodouble(a);
1385: xbig = gtodouble(b);
1386: ysml = ybig = gtodouble(p1);
1387: nc=1; nl=2; /* nc = nb of curves; nl = nb of coord. lists */
1388: if (param)
1389: err(warner,"flag PLOT_PARAMETRIC ignored");
1390: single_c=1; param=0;
1391: }
1392: else
1393: {
1394: if (tx != t_VEC) err(talker,"not a row vector in ploth");
1395: nl=lg(p1)-1; if (!nl) { avma=av; return 0; }
1396: single_c=0;
1397: if (param) nc=nl/2; else { nc=nl; nl++; }
1398: if (recur && nc > 1) err(talker,"multi-curves cannot be plot recursively");
1399:
1400: if (param)
1401: {
1402: xbig=xsml=gtodouble((GEN)p1[1]);
1403: ybig=ysml=gtodouble((GEN)p1[2]);
1404: for (i=3; i<=nl; i++)
1405: {
1406: fx=gtodouble((GEN)p1[i]); i++;
1407: fy=gtodouble((GEN)p1[i]);
1408: if (xsml>fx) xsml=fx; else if (xbig<fx) xbig=fx;
1409: if (ysml>fy) ysml=fy; else if (ybig<fy) ybig=fy;
1410: }
1411: }
1412: else
1413: {
1414: xsml=gtodouble(a); xbig=gtodouble(b);
1415: ysml=gtodouble(vecmin(p1)); ybig=gtodouble(vecmax(p1));
1416: }
1417: }
1418:
1419: pl=(dblPointList*) gpmalloc(nl*sizeof(dblPointList));
1420: for (i = 0; i < nl; i++)
1421: {
1422: pl[i].d = (double*) gpmalloc((nbpoints+1)*sizeof(dblPointList));
1423: pl[i].nb=0;
1424: }
1425: pl[0].xsml=xsml; pl[0].ysml=ysml; pl[0].xbig=xbig; pl[0].ybig=ybig;
1426:
1427: if (recur) /* recursive plot */
1428: {
1429: xleft=cgetr(3); xright=cgetr(3); yleft=cgetr(3); yright=cgetr(3);
1430: if (param)
1431: {
1432: tleft=cgetr(prec); tright=cgetr(prec);
1433: av2=avma;
1434: gaffect(a,tleft); ep->value = (void*)tleft; p1=READ_EXPR(ch);
1435: gaffect((GEN)p1[1],xleft); gaffect((GEN)p1[2],yleft);
1436: for (i=0; i<testpoints-1; i++)
1437: {
1438: if (i) {
1439: gaffect(tright,tleft); gaffect(xright,xleft); gaffect(yright,yleft);
1440: }
1441: gaddz(tleft,dx,tright); ep->value = (void*)tright;
1442: p1 = READ_EXPR(ch);
1443: if (lg(p1) != 3) err(talker,"inconsistent data in rectplothin");
1444: gaffect((GEN)p1[1],xright); gaffect((GEN)p1[2],yright);
1445:
1446: Appendx(&pl[0],&pl[0],rtodbl(xleft));
1447: Appendy(&pl[0],&pl[1],rtodbl(yleft));
1448:
1449: param_recursion(pl,ch,ep, tleft,xleft,yleft, tright,xright,yright, 0);
1450: avma=av2;
1451: }
1452: Appendx(&pl[0],&pl[0],rtodbl(xright));
1453: Appendy(&pl[0],&pl[1],rtodbl(yright));
1454: }
1455: else /* single_c */
1456: {
1457: av2=avma;
1458: gaffect(a,xleft); ep->value = (void*) xleft;
1459: gaffect(READ_EXPR(ch),yleft);
1460: for (i=0; i<testpoints-1; i++)
1461: {
1462: gaddz(xleft,dx,xright); ep->value = (void*) xright;
1463: gaffect(READ_EXPR(ch),yright);
1464:
1465: Appendx(&pl[0],&pl[0],rtodbl(xleft));
1466: Appendy(&pl[0],&pl[1],rtodbl(yleft));
1467:
1468: single_recursion(pl,ch,ep,xleft,yleft,xright,yright,0);
1469: avma=av2;
1470: gaffect(xright,xleft); gaffect(yright,yleft);
1471: }
1472: Appendx(&pl[0],&pl[0],rtodbl(xright));
1473: Appendy(&pl[0],&pl[1],rtodbl(yright));
1474: }
1475: }
1476: else /* non-recursive plot */
1477: {
1478: if (single_c)
1479: for (i=0; i<testpoints; i++)
1480: {
1481: p1 = READ_EXPR(ch);
1482: pl[0].d[i]=gtodouble(x);
1483: Appendy(&pl[0],&pl[1],gtodouble(p1));
1484: gaddz(x,dx,x); avma=av2;
1485: }
1486: else if (param)
1487: {
1488: long k;
1489: double z;
1490:
1491: for (i=0; i<testpoints; i++)
1492: {
1493: p1 = READ_EXPR(ch);
1494: if (lg(p1) != nl+1) err(talker,"inconsistent data in rectplothin");
1495: for (j=0; j<nl; j=k)
1496: {
1497: k=j+1; z=gtodouble((GEN)p1[k]);
1498: Appendx(&pl[0], &pl[j],z);
1499:
1500: j=k; k++; z=gtodouble((GEN)p1[k]);
1501: Appendy(&pl[0], &pl[j],z);
1502: }
1503: gaddz(x,dx,x); avma=av2;
1504: }
1505: }
1506: else /* plothmult */
1507: for (i=0; i<testpoints; i++)
1508: {
1509: p1 = READ_EXPR(ch);
1510: if (lg(p1) != nl) err(talker,"inconsistent data in rectplothin");
1511: pl[0].d[i]=gtodouble(x);
1512: for (j=1; j<nl; j++) { Appendy(&pl[0],&pl[j],gtodouble((GEN)p1[j])); }
1513: gaddz(x,dx,x); avma=av2;
1514: }
1515: }
1516: pl[0].nb=nc; pop_val(ep); avma = av;
1517: return pl;
1518: }
1519:
1520: extern GEN polint_i(GEN xa, GEN ya, GEN x, long n, GEN *ptdy);
1521:
1522: /* Uses highlevel plotting functions to implement splines as
1523: a low-level plotting function.
1524: Most probably one does not need to make varn==0 into pure variable,
1525: since plotting functions should take care of this. */
1526: static void
1527: rectsplines(long ne, double *x, double *y, long lx, long flag)
1528: {
1529: long i, j, oldavma = avma;
1530: GEN tas, xa = cgetg(lx+1, t_VEC), ya = cgetg(lx+1, t_VEC);
1531: entree *var0 = varentries[ordvar[0]];
1532:
1533: if (lx < 4)
1534: err(talker, "Too few points (%ld) for spline plot", lx);
1535: for (i = 1; i <= lx; i++) {
1536: xa[i] = (long) dbltor(x[i-1]);
1537: ya[i] = (long) dbltor(y[i-1]);
1538: }
1539: if (flag & PLOT_PARAMETRIC) {
1540: tas = new_chunk(4);
1541: for (j = 1; j <= 4; j++) tas[j-1] = lstoi(j);
1542: quark_gen = cgetg(2 + 1, t_VEC);
1543: }
1544: else tas = NULL; /* for lint */
1545: for (i = 0; i <= lx - 4; i++) {
1546: long oavma = avma;
1547:
1548: xa++; ya++;
1549: if (flag & PLOT_PARAMETRIC) {
1550: quark_gen[1] = (long)polint_i(tas, xa, polx[0], 4, NULL);
1551: quark_gen[2] = (long)polint_i(tas, ya, polx[0], 4, NULL);
1552: } else {
1553: quark_gen = polint_i(xa, ya, polx[0], 4, NULL);
1554: tas = xa;
1555: }
1556: rectploth(ne, var0,
1557: (GEN)(i==0 ? tas[0] : tas[1]),
1558: (GEN)(i==lx-4 ? tas[3] : tas[2]),
1559: QUARK,
1560: DEFAULTPREC, /* XXXX precision */
1561: PLOT_RECURSIVE
1562: | PLOT_NO_RESCALE
1563: | PLOT_NO_FRAME
1564: | PLOT_NO_AXE_Y
1565: | PLOT_NO_AXE_X
1566: | (flag & PLOT_PARAMETRIC),
1567: 2); /* Start with 3 points */
1568: avma = oavma;
1569: }
1570: avma = oldavma;
1571: }
1572:
1573: /*
1574: * Plot a dblPointList. Complete with axes, bounding box, etc.
1575: * We use two drawing rectangles: one for strings, another
1576: * for graphs.
1577: *
1578: * data is an array of structs. Its meaning depends on flags :
1579: *
1580: * + data[0] contains global extremas, the number of curves to plot
1581: * (data[0].nb) and a list of doubles (first set of x-coordinates).
1582: *
1583: * + data[i].nb (i>0) contains the number of points in the list
1584: * data[i].d (hopefully, data[2i].nb=data[2i+1].nb when i>0...)
1585: *
1586: * + If flags contain PLOT_PARAMETRIC, the array length should be
1587: * even, and successive pairs (data[2i].d, data[2i+1].d) represent
1588: * curves to plot.
1589: *
1590: * + If there is no such flag, the first element is an array with
1591: * x-coordinates and the following ones contain y-coordinates.
1592: *
1593: * Additional flags: PLOT_NO_AXE_X, PLOT_NO_AXE_Y, PLOT_NO_FRAME.
1594: */
1595:
1596: static GEN
1597: rectplothrawin(long stringrect, long drawrect, dblPointList *data,
1598: long flags, PARI_plot *WW)
1599: {
1600: GEN res;
1601: dblPointList y,x;
1602: double xsml,xbig,ysml,ybig,tmp;
1603: long ltype, ltop=avma;
1604: long i,nc,nbpoints, w[2], wx[2], wy[2];
1605:
1606: w[0]=stringrect; w[1]=drawrect;
1607: if (!data) return cgetg(1,t_VEC);
1608: x = data[0]; nc = x.nb;
1609: xsml = x.xsml; xbig = x.xbig;
1610: ysml = x.ysml; ybig = x.ybig;
1611: if (xbig-xsml < 1.e-9)
1612: {
1613: tmp=fabs(xsml)/10; if (!tmp) tmp=0.1;
1614: xbig+=tmp; xsml-=tmp;
1615: }
1616: if (ybig-ysml < 1.e-9)
1617: {
1618: tmp=fabs(ysml)/10; if (!tmp) tmp=0.1;
1619: ybig+=tmp; ysml-=tmp;
1620: }
1621:
1622: if (WW)
1623: { /* no rectwindow supplied ==> ps or screen output */
1624: char c1[16],c2[16],c3[16],c4[16];
1625: PARI_plot W = *WW;
1626: long lm = W.fwidth*10; /* left margin */
1627: long rm = W.hunit-1; /* right margin */
1628: long tm = W.vunit-1; /* top margin */
1629: long bm = W.vunit+W.fheight-1; /* bottom margin */
1630: long is = W.width - (lm+rm);
1631: long js = W.height - (tm+bm);
1632:
1633: wx[0]=wy[0]=0; wx[1]=lm; wy[1]=tm;
1634: /* Window size (W.width x W.height) is given in pixels, and
1635: * correct pixels are 0..w_width-1.
1636: * On the other hand, rect functions work with windows whose pixel
1637: * range is [0,width]. */
1638: initrect(stringrect, W.width-1, W.height-1);
1639: if (drawrect != stringrect) initrect(drawrect, is-1, js-1);
1640:
1641: /* draw labels on stringrect */
1642: sprintf(c1,"%.5g",ybig); sprintf(c2,"%.5g",ysml);
1643: sprintf(c3,"%.5g",xsml); sprintf(c4,"%.5g",xbig);
1644:
1645: rectlinetype(stringrect,-2); /* Frame */
1646: current_color[stringrect]=BLACK;
1647: put_string( stringrect, lm, 0, c1,
1648: RoSTdirRIGHT | RoSTdirHGAP | RoSTdirTOP);
1649: put_string(stringrect, lm, W.height - bm, c2,
1650: RoSTdirRIGHT | RoSTdirHGAP | RoSTdirVGAP);
1651: put_string(stringrect, lm, W.height - bm, c3,
1652: RoSTdirLEFT | RoSTdirTOP);
1653: put_string(stringrect, W.width - rm - 1, W.height - bm, c4,
1654: RoSTdirRIGHT | RoSTdirTOP);
1655: }
1656: RHasGraph(check_rect(drawrect)) = 1;
1657:
1658: if (!(flags & PLOT_NO_RESCALE))
1659: rectscale0(drawrect, xsml, xbig, ysml, ybig);
1660:
1661: if (!(flags & PLOT_NO_FRAME))
1662: {
1663: int do_double = (flags & PLOT_NODOUBLETICK) ? TICKS_NODOUBLE : 0;
1664:
1665: rectlinetype(drawrect, -2); /* Frame. */
1666: current_color[drawrect]=BLACK;
1667: rectmove0(drawrect,xsml,ysml,0);
1668: rectbox0(drawrect,xbig,ybig,0);
1669: if (!(flags & PLOT_NO_TICK_X)) {
1670: rectticks(WW, drawrect, xsml, ysml, xbig, ysml, xsml, xbig,
1671: TICKS_CLOCKW | do_double);
1672: rectticks(WW, drawrect, xbig, ybig, xsml, ybig, xbig, xsml,
1673: TICKS_CLOCKW | do_double);
1674: }
1675: if (!(flags & PLOT_NO_TICK_Y)) {
1676: rectticks(WW, drawrect, xbig, ysml, xbig, ybig, ysml, ybig,
1677: TICKS_CLOCKW | do_double);
1678: rectticks(WW, drawrect, xsml, ybig, xsml, ysml, ybig, ysml,
1679: TICKS_CLOCKW | do_double);
1680: }
1681: }
1682:
1683: if (!(flags & PLOT_NO_AXE_Y) && (xsml<=0 && xbig >=0))
1684: {
1685: rectlinetype(drawrect, -1); /* Axes. */
1686: current_color[drawrect]=BLUE;
1687: rectmove0(drawrect,0.0,ysml,0);
1688: rectline0(drawrect,0.0,ybig,0);
1689: }
1690:
1691: if (!(flags & PLOT_NO_AXE_X) && (ysml<=0 && ybig >=0))
1692: {
1693: rectlinetype(drawrect, -1); /* Axes. */
1694: current_color[drawrect]=BLUE;
1695: rectmove0(drawrect,xsml,0.0,0);
1696: rectline0(drawrect,xbig,0.0,0);
1697: }
1698:
1699: i = (flags & PLOT_PARAMETRIC)? 0: 1;
1700: for (ltype = 0; ltype < nc; ltype++)
1701: {
1702: current_color[drawrect] = ltype&1 ? SIENNA: RED;
1703: if (flags & PLOT_PARAMETRIC) x = data[i++];
1704:
1705: y=data[i++]; nbpoints=y.nb;
1706: if ((flags & PLOT_POINTS_LINES) || (flags & PLOT_POINTS)) {
1707: rectlinetype(drawrect, rectpoint_itype + ltype); /* Graphs. */
1708: rectpointtype(drawrect, rectpoint_itype + ltype); /* Graphs. */
1709: rectpoints0(drawrect,x.d,y.d,nbpoints);
1710: }
1711: if ((flags & PLOT_POINTS_LINES) || !(flags & PLOT_POINTS)) {
1712: if (flags & PLOT_SPLINES) {
1713: /* rectsplines will call us back with ltype == 0 */
1714: int old = rectline_itype;
1715:
1716: rectline_itype = rectline_itype + ltype;
1717: rectsplines(drawrect,x.d,y.d,nbpoints,flags);
1718: rectline_itype = old;
1719: } else {
1720: rectlinetype(drawrect, rectline_itype + ltype); /* Graphs. */
1721: rectlines0(drawrect,x.d,y.d,nbpoints,0);
1722: }
1723: }
1724: }
1725: for (i--; i>=0; i--) free(data[i].d);
1726: free(data);
1727:
1728: if (WW)
1729: {
1730: if (flags & PLOT_POSTSCRIPT)
1731: postdraw0(w,wx,wy,2);
1732: else
1733: rectdraw0(w,wx,wy,2, 0);
1734:
1735: killrect(drawrect); if (stringrect != drawrect) killrect(stringrect);
1736: }
1737:
1738: avma=ltop;
1739: res = cgetg(5,t_VEC);
1740: res[1]=(long)dbltor(xsml); res[2]=(long)dbltor(xbig);
1741: res[3]=(long)dbltor(ysml); res[4]=(long)dbltor(ybig);
1742: return res;
1743: }
1744:
1745: /*************************************************************************/
1746: /* */
1747: /* HI-RES FUNCTIONS */
1748: /* */
1749: /*************************************************************************/
1750:
1751: GEN
1752: rectploth(long drawrect,entree *ep,GEN a,GEN b,char *ch,
1753: long prec,ulong flags,long testpoints)
1754: {
1755: dblPointList *pl=rectplothin(ep, a,b, ch, prec, flags,testpoints);
1756: return rectplothrawin(0,drawrect, pl, flags,NULL);
1757: }
1758:
1759: GEN
1760: rectplothraw(long drawrect, GEN data, long flags)
1761: {
1762: dblPointList *pl=gtodblList(data,flags);
1763: return rectplothrawin(0,drawrect,pl,flags,NULL);
1764: }
1765:
1766: static PARI_plot*
1767: init_output(long flags)
1768: {
1769: if (flags & PLOT_POSTSCRIPT)
1770: { PARI_get_psplot(); return &pari_psplot; }
1771: else
1772: { PARI_get_plot(0); return &pari_plot; }
1773: }
1774:
1775: static GEN
1776: ploth0(long stringrect,long drawrect,entree *ep,GEN a,GEN b,char *ch,
1777: long prec,ulong flags,long testpoints)
1778: {
1779: PARI_plot *output = init_output(flags);
1780: dblPointList *pl=rectplothin(ep, a,b, ch, prec, flags,testpoints);
1781: return rectplothrawin(stringrect,drawrect, pl, flags, output);
1782: }
1783:
1784: static GEN
1785: plothraw0(long stringrect, long drawrect, GEN listx, GEN listy, long flags)
1786: {
1787: PARI_plot *output = init_output(flags);
1788: long data[] = {evaltyp(t_VEC) | m_evallg(3), 0, 0};
1789: dblPointList *pl;
1790:
1791: data[1] = (long) listx;
1792: data[2] = (long) listy;
1793: pl=gtodblList(data,PLOT_PARAMETRIC);
1794: if (!pl) return cgetg(1,t_VEC);
1795: return rectplothrawin(stringrect,drawrect,pl,flags | PLOT_PARAMETRIC,output);
1796: }
1797:
1798: GEN
1799: plothraw(GEN listx, GEN listy, long flags)
1800: {
1801: flags = (flags > 1 ? flags : (flags ? 0: PLOT_POINTS));
1802: return plothraw0(STRINGRECT, DRAWRECT, listx, listy, flags);
1803: }
1804:
1805: GEN
1806: ploth(entree *ep, GEN a, GEN b, char *ch, long prec,long flags,long numpoints)
1807: {
1808: return ploth0(STRINGRECT, DRAWRECT, ep,a,b,ch,prec,flags,numpoints);
1809: }
1810:
1811: GEN
1812: ploth2(entree *ep, GEN a, GEN b, char *ch, long prec)
1813: {
1814: return ploth0(STRINGRECT, DRAWRECT, ep,a,b,ch,prec,PLOT_PARAMETRIC,0);
1815: }
1816:
1817: GEN
1818: plothmult(entree *ep, GEN a, GEN b, char *ch, long prec)
1819: {
1820: return ploth0(STRINGRECT, DRAWRECT, ep,a,b,ch,prec,0,0);
1821: }
1822:
1823: GEN
1824: postplothraw(GEN listx, GEN listy, long flags)
1825: {
1826: flags=(flags)? 0: PLOT_POINTS;
1827: return plothraw0(STRINGRECT, DRAWRECT, listx, listy, flags|PLOT_POSTSCRIPT);
1828: }
1829:
1830: GEN
1831: postploth(entree *ep, GEN a, GEN b, char *ch, long prec,long flags,
1832: long numpoints)
1833: {
1834: return ploth0(STRINGRECT,DRAWRECT,ep,a,b,ch,prec,flags|PLOT_POSTSCRIPT,
1835: numpoints);
1836: }
1837:
1838: GEN
1839: postploth2(entree *ep, GEN a, GEN b, char *ch, long prec,
1840: long numpoints)
1841: {
1842: return ploth0(STRINGRECT,DRAWRECT,ep,a,b,ch,prec,
1843: PLOT_PARAMETRIC|PLOT_POSTSCRIPT,numpoints);
1844: }
1845:
1846: GEN
1847: plothsizes()
1848: {
1849: return plothsizes_flag(0);
1850: }
1851:
1852: GEN
1853: plothsizes_flag(long flag)
1854: {
1855: GEN vect = cgetg(1+6,t_VEC);
1856:
1857: PARI_get_plot(0);
1858: vect[1] = lstoi(w_width);
1859: vect[2] = lstoi(w_height);
1860: if (flag) {
1861: vect[3] = (long)dbltor(h_unit*1.0/w_width);
1862: vect[4] = (long)dbltor(v_unit*1.0/w_height);
1863: vect[5] = (long)dbltor(f_width*1.0/w_width);
1864: vect[6] = (long)dbltor(f_height*1.0/w_height);
1865: } else {
1866: vect[3] = lstoi(h_unit);
1867: vect[4] = lstoi(v_unit);
1868: vect[5] = lstoi(f_width);
1869: vect[6] = lstoi(f_height);
1870: }
1871: return vect;
1872: }
1873:
1874: /*************************************************************************/
1875: /* */
1876: /* POSTSCRIPT OUTPUT */
1877: /* */
1878: /*************************************************************************/
1879:
1880: typedef struct spoint {
1881: int x,y; } SPoint;
1882: typedef struct ssegment {
1883: int x1,y1,x2,y2; } SSegment;
1884: typedef struct srectangle {
1885: int x,y,width,height; } SRectangle;
1886:
1887: static void ps_point(FILE *psfile, int x, int y);
1888: static void ps_line(FILE *psfile, int x1, int y1, int x2, int y2);
1889: static void ps_rect(FILE *psfile, int x1, int y1, int x2, int y2);
1890: static void ps_string(FILE *psfile, int x, int y, char *c, long dir);
1891:
1892: #undef ISCR
1893: #undef JSCR
1894: #define ISCR 1120 /* 1400 en haute resolution */
1895: #define JSCR 800 /* 1120 en haute resolution */
1896:
1897: static void
1898: PARI_get_psplot()
1899: {
1900: pari_psplot.height = JSCR - 60;
1901: pari_psplot.width = ISCR - 40;
1902: pari_psplot.fheight = 15;
1903: pari_psplot.fwidth = 6;
1904: pari_psplot.hunit = 5;
1905: pari_psplot.vunit = 5;
1906: }
1907:
1908: static void
1909: gendraw(GEN list, long ps, long flag)
1910: {
1911: long i,n,ne,*w,*x,*y;
1912: GEN x0,y0,win;
1913:
1914: if (typ(list) != t_VEC) err(talker,"not a vector in rectdraw");
1915: n = lg(list)-1;
1916: if (n%3) err(talker,"incorrect number of components in rectdraw");
1917: n = n/3; if (!n) return;
1918: w = (long*)gpmalloc(n*sizeof(long));
1919: x = (long*)gpmalloc(n*sizeof(long));
1920: y = (long*)gpmalloc(n*sizeof(long));
1921: if (flag)
1922: PARI_get_plot(0);
1923: for (i=0; i<n; i++)
1924: {
1925: win=(GEN)list[3*i+1]; x0=(GEN)list[3*i+2]; y0=(GEN)list[3*i+3];
1926: if (typ(win)!=t_INT || (!flag && (typ(x0)!=t_INT || typ(y0)!= t_INT)))
1927: err(talker, "not an integer type in rectdraw");
1928: if (flag) {
1929: double xd = gtodouble(x0), yd = gtodouble(y0);
1930: long xi, yi;
1931:
1932: xi = w_width - 1; yi = w_height - 1;
1933: xi = (long)(xd*xi + 0.5);
1934: yi = (long)(yd*yi + 0.5);
1935: x[i] = xi; y[i] = yi;
1936: } else {
1937: x[i]=itos(x0); y[i]=itos(y0);
1938: }
1939: ne=itos(win); check_rect(ne);
1940: w[i]=ne;
1941: }
1942: if (ps) postdraw00(w,x,y,n,flag); else rectdraw0(w,x,y,n, 1);
1943: free(x); free(y); free(w);
1944: }
1945:
1946: void
1947: postdraw(GEN list) { gendraw(list, 1, 0); }
1948:
1949: void
1950: rectdraw(GEN list) { gendraw(list, 0, 0); }
1951:
1952: void
1953: postdraw_flag(GEN list, long flag) { gendraw(list, 1, flag); }
1954:
1955: void
1956: rectdraw_flag(GEN list, long flag) { gendraw(list, 0, flag); }
1957:
1958: static char*
1959: zmalloc(size_t x)
1960: {
1961: return x? gpmalloc(x): NULL;
1962: }
1963:
1964: void
1965: postdraw0(long *w, long *x, long *y, long lw)
1966: {
1967: postdraw00(w, x, y, lw, 0);
1968: }
1969:
1970: void
1971: postdraw00(long *w, long *x, long *y, long lw, long scale)
1972: {
1973: double *ptx,*pty;
1974: long *numpoints,*numtexts,*xtexts,*ytexts,*dirtexts;
1975: RectObj *p1;
1976: PariRect *e;
1977: long i,j,x0,y0;
1978: long a,b,c,d,nd[ROt_MAX+1];
1979: char **texts;
1980: FILE *psfile;
1981: double xscale = 0.65, yscale = 0.65;
1982: long fontsize = 16, xtick = 5, ytick = 5;
1983:
1984: SPoint *points, **lines, *SLine;
1985: SSegment *seg;
1986: SRectangle *rect, SRec;
1987:
1988: if (scale) {
1989: double postxsize, postysize;
1990:
1991: PARI_get_psplot();
1992: postxsize = pari_psplot.width;
1993: postysize = pari_psplot.height;
1994: PARI_get_plot(0);
1995: xscale *= postxsize * 1.0/w_width;
1996: fontsize = (long) (fontsize/(postxsize * 1.0/w_width));
1997: yscale *= postysize * 1.0/w_height;
1998: xtick = h_unit; ytick = v_unit;
1999: }
2000: psfile = fopen(current_psfile, "a");
2001: if (!psfile)
2002: err(openfiler,"postscript",current_psfile);
2003:
2004: for (i=0; i<=ROt_MAX; i++) nd[i]=0;
2005:
2006: for (i=0; i<lw; i++)
2007: {
2008: e = check_rect_init(w[i]); p1=RHead(e);
2009: while (p1)
2010: {
2011: if (RoType(p1) != ROt_MP) nd[RoType(p1)]++;
2012: else nd[ROt_PT]+=RoMPcnt(p1);
2013: p1=RoNext(p1);
2014: }
2015: }
2016: points=(SPoint*) zmalloc(nd[ROt_PT]*sizeof(SPoint));
2017: seg=(SSegment*) zmalloc(nd[ROt_LN]*sizeof(SSegment));
2018: rect=(SRectangle*) zmalloc(nd[ROt_BX]*sizeof(SRectangle));
2019: lines=(SPoint**) zmalloc(nd[ROt_ML]*sizeof(SPoint*));
2020: numpoints=(long*) zmalloc(nd[ROt_ML]*sizeof(long));
2021: texts=(char**) zmalloc(nd[ROt_ST]*sizeof(char*));
2022: numtexts=(long*) zmalloc(nd[ROt_ST]*sizeof(long));
2023: xtexts = (long*) zmalloc(nd[ROt_ST]*sizeof(long));
2024: ytexts = (long*) zmalloc(nd[ROt_ST]*sizeof(long));
2025: dirtexts = (long*) zmalloc(nd[ROt_ST]*sizeof(long));
2026: for (i=0; i<=ROt_MAX; i++) nd[i]=0;
2027:
2028: for (i=0; i<lw; i++)
2029: {
2030: e=rectgraph[w[i]]; p1=RHead(e); x0=x[i]; y0=y[i];
2031: while (p1)
2032: {
2033: switch(RoType(p1))
2034: {
2035: case ROt_PT:
2036: points[nd[ROt_PT]].x = DTOL(RoPTx(p1)+x0);
2037: points[nd[ROt_PT]].y = DTOL(RoPTy(p1)+y0);
2038: nd[ROt_PT]++; break;
2039: case ROt_LN:
2040: seg[nd[ROt_LN]].x1 = DTOL(RoLNx1(p1)+x0);
2041: seg[nd[ROt_LN]].y1 = DTOL(RoLNy1(p1)+y0);
2042: seg[nd[ROt_LN]].x2 = DTOL(RoLNx2(p1)+x0);
2043: seg[nd[ROt_LN]].y2 = DTOL(RoLNy2(p1)+y0);
2044: nd[ROt_LN]++; break;
2045: case ROt_BX:
2046: a=rect[nd[ROt_BX]].x = DTOL(RoBXx1(p1)+x0);
2047: b=rect[nd[ROt_BX]].y = DTOL(RoBXy1(p1)+y0);
2048: rect[nd[ROt_BX]].width = DTOL(RoBXx2(p1)+x0-a);
2049: rect[nd[ROt_BX]].height = DTOL(RoBXy2(p1)+y0-b);
2050: nd[ROt_BX]++; break;
2051: case ROt_MP:
2052: ptx = RoMPxs(p1); pty = RoMPys(p1);
2053: for (j=0; j<RoMPcnt(p1); j++)
2054: {
2055: points[nd[ROt_PT]+j].x = DTOL(ptx[j]+x0);
2056: points[nd[ROt_PT]+j].y = DTOL(pty[j]+y0);
2057: }
2058: nd[ROt_PT]+=RoMPcnt(p1); break;
2059: case ROt_ML:
2060: ptx=RoMLxs(p1); pty=RoMLys(p1);
2061: numpoints[nd[ROt_ML]]=RoMLcnt(p1);
2062: lines[nd[ROt_ML]]=(SPoint*)gpmalloc(RoMLcnt(p1)*sizeof(SPoint));
2063: for (j=0; j<RoMLcnt(p1); j++)
2064: {
2065: lines[nd[ROt_ML]][j].x = DTOL(ptx[j]+x0);
2066: lines[nd[ROt_ML]][j].y = DTOL(pty[j]+y0);
2067: }
2068: nd[ROt_ML]++; break;
2069: case ROt_ST:
2070: texts[nd[ROt_ST]] = RoSTs(p1);
2071: numtexts[nd[ROt_ST]] = RoSTl(p1);
2072: xtexts[nd[ROt_ST]] = DTOL(RoSTx(p1)+x0);
2073: ytexts[nd[ROt_ST]] = DTOL(RoSTy(p1)+y0);
2074: dirtexts[nd[ROt_ST]] = RoSTdir(p1);
2075: nd[ROt_ST]++; break;
2076: default: break;
2077: }
2078: p1=RoNext(p1);
2079: }
2080: }
2081: /* Definitions taken from post terminal of Gnuplot. */
2082: fprintf(psfile,"%%!\n50 50 translate\n/Times-Roman findfont %ld scalefont setfont\n%g %g scale\n", fontsize, yscale,xscale);
2083: fprintf(psfile,"/Lshow { moveto 90 rotate show -90 rotate } def\n/Rshow { 3 -1 roll dup 4 1 roll stringwidth pop sub Lshow } def\n/Cshow { 3 -1 roll dup 4 1 roll stringwidth pop 2 div sub Lshow } def\n");
2084: fprintf(psfile,"/Xgap %ld def\n/Ygap %ld def\n", xtick, ytick);
2085: fprintf(psfile,"/Bbox { gsave newpath 0 0 moveto true charpath pathbbox grestore } def\n");
2086: fprintf(psfile,"/Height { Bbox 4 1 roll pop pop pop } def\n");
2087: fprintf(psfile,"/TopAt { 3 -1 roll dup 4 1 roll Height 3 -1 roll add exch } def\n");
2088: fprintf(psfile,"/VCenter { 3 -1 roll dup 4 1 roll Height 2 div 3 -1 roll add exch } def\n");
2089: fprintf(psfile,"/Tgap { exch Ygap add exch } def\n");
2090: fprintf(psfile,"/Bgap { exch Ygap sub exch } def\n");
2091: fprintf(psfile,"/Lgap { Xgap add } def\n");
2092: fprintf(psfile,"/Rgap { Xgap sub } def\n");
2093:
2094: for (i=0; i<nd[ROt_PT]; i++)
2095: ps_point(psfile,points[i].x,points[i].y);
2096: for (i=0; i<nd[ROt_LN]; i++)
2097: ps_line(psfile,seg[i].x1,seg[i].y1,seg[i].x2,seg[i].y2);
2098: for (i=0; i<nd[ROt_BX]; i++)
2099: {
2100: SRec=rect[i]; a=SRec.x; b=SRec.y; c=a+SRec.width;
2101: d=b+SRec.height; ps_rect(psfile,a,b,c,d);
2102: }
2103: for (i=0; i<nd[ROt_ML]; i++)
2104: {
2105: SLine=lines[i];
2106: for (j=0; j<numpoints[i]; j++)
2107: {
2108: if (!j) fprintf(psfile,"%d %d moveto\n",SLine[0].y,SLine[0].x);
2109: else fprintf(psfile,"%d %d lineto\n",SLine[j].y,SLine[j].x);
2110: }
2111: }
2112: for (i=0; i<nd[ROt_ST]; i++)
2113: ps_string(psfile,xtexts[i],ytexts[i],texts[i], dirtexts[i]);
2114: fprintf(psfile,"stroke showpage\n"); fclose(psfile);
2115: #define xfree(pointer) if (pointer) free(pointer)
2116: xfree(points); xfree(seg); xfree(rect); xfree(numpoints);
2117: for (i=0; i<nd[ROt_ML]; i++) xfree(lines[i]);
2118: xfree(lines); xfree(texts); xfree(numtexts); xfree(xtexts); xfree(ytexts);
2119: #undef xfree
2120: }
2121:
2122: static void
2123: ps_point(FILE *psfile, int x, int y)
2124: {
2125: fprintf(psfile,"%d %d moveto\n0 2 rlineto 2 0 rlineto 0 -2 rlineto closepath fill\n",y,x);
2126: }
2127:
2128: static void
2129: ps_line(FILE *psfile, int x1, int y1, int x2, int y2)
2130: {
2131: fprintf(psfile,"%d %d moveto\n%d %d lineto\n",y1,x1,y2,x2);
2132: }
2133:
2134: static void
2135: ps_rect(FILE *psfile, int x1, int y1, int x2, int y2)
2136: {
2137: fprintf(psfile,"%d %d moveto\n%d %d lineto\n%d %d lineto\n%d %d lineto\nclosepath\n",y1,x1,y1,x2,y2,x2,y2,x1);
2138: }
2139:
2140: static void
2141: ps_string(FILE *psfile, int x, int y, char *s, long dir)
2142: {
2143: if (strpbrk(s, "(\\)")) {
2144: fprintf(psfile,"(");
2145: while (*s) {
2146: if ( *s=='(' || *s==')' || *s=='\\' )
2147: fputc('\\', psfile);
2148: fputc(*s, psfile);
2149: s++;
2150: }
2151: } else
2152: fprintf(psfile,"(%s", s);
2153: fprintf(psfile,") %d %d %s%s%s%sshow\n",
2154: y, x,
2155: ((dir & RoSTdirVGAP)
2156: ? ((dir & RoSTdirVPOS_mask) == RoSTdirTOP ? "Tgap " : "Bgap ")
2157: : ""),
2158: ((dir & RoSTdirHGAP)
2159: ? ((dir & RoSTdirHPOS_mask) == RoSTdirRIGHT ? "Rgap " : "Lgap ")
2160: : ""),
2161: ((dir & RoSTdirVPOS_mask) == RoSTdirBOTTOM ? ""
2162: : (dir & RoSTdirVPOS_mask) == RoSTdirTOP ? "TopAt " : "VCenter "),
2163: ((dir & RoSTdirHPOS_mask) == RoSTdirLEFT ? "L"
2164: : ((dir & RoSTdirHPOS_mask) == RoSTdirRIGHT ? "R" : "C")));
2165: }
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>