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