~ubuntu-branches/ubuntu/saucy/python-scipy/saucy

« back to all changes in this revision

Viewing changes to Lib/sandbox/xplt/src/gist/draw.c

  • Committer: Bazaar Package Importer
  • Author(s): Ondrej Certik
  • Date: 2008-06-16 22:58:01 UTC
  • mfrom: (2.1.24 intrepid)
  • Revision ID: james.westby@ubuntu.com-20080616225801-irdhrpcwiocfbcmt
Tags: 0.6.0-12
* The description updated to match the current SciPy (Closes: #489149).
* Standards-Version bumped to 3.8.0 (no action needed)
* Build-Depends: netcdf-dev changed to libnetcdf-dev

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
/*
2
 
 * DRAW.C
3
 
 *
4
 
 * $Id: draw.c 685 2003-03-08 15:26:51Z travo $
5
 
 *
6
 
 * Implement display list portion of GIST C interface
7
 
 *
8
 
 */
9
 
/*    Copyright (c) 1994.  The Regents of the University of California.
10
 
                    All rights reserved.  */
11
 
 
12
 
#include "draw.h"
13
 
#include "gtext.h"
14
 
#include "pstdlib.h"
15
 
 
16
 
/* Generating default contour labels requires sprintf function */
17
 
#include <stdio.h>
18
 
 
19
 
#include <string.h>
20
 
 
21
 
extern double log10(double);
22
 
#define SAFELOG0 (-999.)
23
 
#define SAFELOG(x) ((x)>0? log10(x) : ((x)<0? log10(-(x)) : -999.))
24
 
 
25
 
/* In tick.c */
26
 
extern GpReal GpNiceUnit(GpReal finest, int *base, int *power);
27
 
 
28
 
extern double floor(double);
29
 
extern double ceil(double);
30
 
#ifndef NO_EXP10
31
 
  extern double exp10(double);
32
 
#else
33
 
# define exp10(x) pow(10.,x)
34
 
  extern double pow(double,double);
35
 
#endif
36
 
#define LOG2 0.301029996
37
 
 
38
 
/* ------------------------------------------------------------------------ */
39
 
 
40
 
static Drauing *currentDr= 0;  /* Drauing from GdNewDrawing or GdGetDrawing */
41
 
static GeSystem *currentSy;    /* System from GdNewSystem or GdSetSystem */
42
 
static GdElement *currentEl;   /* Element extracted with GdSetSystem, or
43
 
                                  GdGetElement */
44
 
static int currentCn;          /* level selected by GdGetContour */
45
 
 
46
 
/* Saved state information used by GdSetDrawing */
47
 
static Drauing *saveDr= 0;
48
 
static GeSystem *saveSy; 
49
 
static GdElement *saveEl;
50
 
static int saveCn;
51
 
 
52
 
GdProperties gistD= {
53
 
  0, 0,
54
 
  {
55
 
  {7.5, 50., 1.2, 1.2, 4, 1, TICK_L|TICK_U|TICK_OUT|LABEL_L,
56
 
   0.0, 14.0*ONE_POINT,
57
 
   {12.*ONE_POINT, 8.*ONE_POINT, 5.*ONE_POINT, 3.*ONE_POINT, 2.*ONE_POINT},
58
 
     {FG_COLOR, L_SOLID, 1.0},
59
 
     {FG_COLOR, L_DOT, 1.0},
60
 
     {FG_COLOR, T_HELVETICA, 14.*ONE_POINT,
61
 
        TX_RIGHT, TH_NORMAL, TV_NORMAL, 1},
62
 
     .425, .5-52.*ONE_POINT},
63
 
  {7.5, 50., 1.2, 1.2, 3, 1, TICK_L|TICK_U|TICK_OUT|LABEL_L,
64
 
   0.0, 14.0*ONE_POINT,
65
 
   {12.*ONE_POINT, 8.*ONE_POINT, 5.*ONE_POINT, 3.*ONE_POINT, 2.*ONE_POINT},
66
 
     {FG_COLOR, L_SOLID, 1.0},
67
 
     {FG_COLOR, L_DOT, 1.0},
68
 
     {FG_COLOR, T_HELVETICA, 14.*ONE_POINT,
69
 
        TX_RIGHT, TH_NORMAL, TV_NORMAL, 1},
70
 
     .25, .5-52.*ONE_POINT},
71
 
  0, {FG_COLOR, L_SOLID, 1.0}
72
 
  },
73
 
  {{ 0.0, 1.0, 0.0, 1.0 }, { 0.0, 1.0, 0.0, 1.0 }},
74
 
  D_XMIN | D_XMAX | D_YMIN | D_YMAX,    /* flags */
75
 
  { 0.0, 1.0, 0.0, 1.0 },               /* limits */
76
 
  0, 0, 0, 0, 0,
77
 
  0.0, 0.0, 0,
78
 
  0.0, 0.0, 0.0, 0.0, 0, 0,             /* GdCells */
79
 
  0, 0,
80
 
  0, { 0, 0, 0, 0, 0, 0 }, 0,           /* noCopy, mesh, region */
81
 
  0, 0,
82
 
  0, 0, 0.0,
83
 
  0, 0, 0,  0 };
84
 
 
85
 
Drauing *gistDrawList= 0;
86
 
 
87
 
static void ClearDrawing(Drauing *drawing);
88
 
static void Damage(GeSystem *sys, GdElement *el);
89
 
static void SquareAdjust(GpReal *umin, GpReal *umax,
90
 
                         GpReal dv, int doMin, int doMax);
91
 
static void NiceAdjust(GpReal *umin, GpReal *umax, int isLog, int isMin);
92
 
static void EqAdjust(GpReal *umin, GpReal *umax);
93
 
static void EmptyAdjust(GpReal *umin, GpReal *umax, int doMin, int doMax);
94
 
static void EqualAdjust(GpReal *umin, GpReal *umax, int doMin, int doMax);
95
 
extern int Gd_DrawRing(void *elv, int xIsLog, int yIsLog,
96
 
                       GeSystem *sys, int t);
97
 
static void InitLegends(int contours, GeSystem *systems, GdElement *elements,
98
 
                        int size);
99
 
static void NextContours(void);
100
 
static int NextRing(void);
101
 
static int NextLegend(void);
102
 
static int BuildLegends(int more, int contours, GeSystem *systems,
103
 
                        GdElement *elements, GeLegendBox *lbox);
104
 
static int MemoryError(void);
105
 
static void *Copy1(const void *orig, long size);
106
 
static void *Copy2(void *x1, const void *orig1, const void *orig2, long size);
107
 
extern void Gd_ScanZ(long n, const GpReal *z, GpReal *zmin, GpReal *zmax);
108
 
static void ScanXY(long n, const GpReal *x, const GpReal *y, GpBox *extrema);
109
 
 
110
 
extern void Gd_NextMeshBlock(long *ii, long *jj, long len, long iMax,
111
 
                             int *reg, int region);
112
 
extern void Gd_MeshXYGet(void *vMeshEl);
113
 
static int AutoMarker(GaLineAttribs *dl, int number);
114
 
extern int Gd_MakeContours(GeContours *con);
115
 
static void GuessBox(GpBox *box, GpBox *viewport, GaTickStyle *ticks);
116
 
static GdElement *NextConCurve(GdElement *el);
117
 
static int GeFindIndex(int id, GeSystem *sys);
118
 
 
119
 
extern void Gd_KillRing(void *elv);
120
 
extern void Gd_KillMeshXY(void *vMeshEl);
121
 
 
122
 
static void (*DisjointKill)(void *el);
123
 
static void (*FilledKill)(void *el);
124
 
static void (*VectorsKill)(void *el);
125
 
static void (*ContoursKill)(void *el);
126
 
static void (*SystemKill)(void *el);
127
 
static int (*LinesGet)(void *el);
128
 
static int (*ContoursGet)(void *el);
129
 
extern void Gd_LinesSubSet(void *el);
130
 
static int (*SystemDraw)(void *el, int xIsLog, int yIsLog);
131
 
 
132
 
/* ------------------------------------------------------------------------ */
133
 
/* Set virtual function tables */
134
 
 
135
 
extern GdOpTable *GetDrawingOpTables(void);  /* in draw0.c */
136
 
static GdOpTable *opTables= 0;
137
 
 
138
 
/* ------------------------------------------------------------------------ */
139
 
/* Constructor and destructor for Drauing declared in gist.h */
140
 
 
141
 
Drauing *GdNewDrawing(char *gsFile)
142
 
{
143
 
  Drauing *drawing= p_malloc(sizeof(Drauing));
144
 
  if (!drawing) return 0;
145
 
  if (!opTables) {
146
 
    opTables= GetDrawingOpTables();
147
 
    DisjointKill= opTables[E_DISJOINT].Kill;
148
 
    FilledKill= opTables[E_FILLED].Kill;
149
 
    VectorsKill= opTables[E_VECTORS].Kill;
150
 
    ContoursKill= opTables[E_CONTOURS].Kill;
151
 
    SystemKill= opTables[E_SYSTEM].Kill;
152
 
    LinesGet= opTables[E_LINES].GetProps;
153
 
    ContoursGet= opTables[E_CONTOURS].GetProps;
154
 
    SystemDraw= opTables[E_SYSTEM].Draw;
155
 
  }
156
 
 
157
 
  drawing->next= gistDrawList;
158
 
  gistDrawList= drawing;
159
 
  drawing->cleared=
160
 
    drawing->nSystems= drawing->nElements= 0;
161
 
  drawing->systems= 0;
162
 
  drawing->elements= 0;
163
 
  drawing->damaged= 0;
164
 
  drawing->damage.xmin= drawing->damage.xmax=
165
 
    drawing->damage.ymin= drawing->damage.ymax= 0.0;
166
 
  drawing->landscape= 0;
167
 
  drawing->legends[0].nlines= drawing->legends[1].nlines= 0;
168
 
 
169
 
  GdSetDrawing(drawing);
170
 
 
171
 
  if (GdReadStyle(drawing, gsFile)) {
172
 
    GdSetDrawing(0);
173
 
    GdKillDrawing(drawing);
174
 
    return 0;
175
 
  }
176
 
 
177
 
  return drawing;
178
 
}
179
 
 
180
 
int GdLandscape(int landscape)
181
 
{
182
 
  if (!currentDr) return 1;
183
 
  if (landscape) landscape= 1;
184
 
  if (currentDr->landscape!=landscape) {
185
 
    currentDr->landscape= landscape;
186
 
    GdDetach(currentDr, 0);
187
 
  }
188
 
  return 0;
189
 
}
190
 
 
191
 
void GdKillDrawing(Drauing *drawing)
192
 
{
193
 
  if (!drawing) {
194
 
    drawing= currentDr;
195
 
    if (!drawing) return;
196
 
  }
197
 
 
198
 
  ClearDrawing(drawing);
199
 
  Gd_KillRing(drawing->systems);
200
 
 
201
 
  if (drawing==gistDrawList) gistDrawList= drawing->next;
202
 
  else {
203
 
    Drauing *draw= gistDrawList;
204
 
    while (draw->next!=drawing) draw= draw->next;
205
 
    draw->next= drawing->next;
206
 
  }
207
 
 
208
 
  if (drawing==currentDr) currentDr= 0;
209
 
 
210
 
  p_free(drawing);
211
 
}
212
 
 
213
 
extern void GdKillSystems(void);
214
 
 
215
 
void GdKillSystems(void)
216
 
{
217
 
  if (!currentDr) return;
218
 
  ClearDrawing(currentDr);
219
 
  Gd_KillRing(currentDr->systems);
220
 
  currentDr->systems= 0;
221
 
  currentDr->nSystems= 0;
222
 
}
223
 
 
224
 
int GdSetDrawing(Drauing *drawing)
225
 
{
226
 
  int nMax, sysIndex, i;
227
 
  GeSystem *sys;
228
 
 
229
 
  if (!drawing) {  /* swap current and saved state info */
230
 
    Drauing *tmpDr= currentDr;
231
 
    GeSystem *tmpSy= currentSy;
232
 
    GdElement *tmpEl= currentEl;
233
 
    int tmpCn= currentCn;
234
 
    currentDr= saveDr;   saveDr= tmpDr;
235
 
    currentSy= saveSy;   saveSy= tmpSy;
236
 
    currentEl= saveEl;   saveEl= tmpEl;
237
 
    currentCn= saveCn;   saveCn= tmpCn;
238
 
    return 0;
239
 
  }
240
 
 
241
 
  saveDr= currentDr;
242
 
  saveSy= currentSy;
243
 
  saveEl= currentEl;
244
 
  saveCn= currentCn;
245
 
 
246
 
  currentDr= drawing;
247
 
 
248
 
  /* Make a reasonable guess at current system and element */
249
 
  nMax= drawing->elements? drawing->elements->prev->number : -1;
250
 
  sysIndex= drawing->nSystems? 1 : 0;
251
 
  i= 0;
252
 
  if ((sys= drawing->systems)) do {
253
 
    i++;
254
 
    if (sys->el.number>nMax) { nMax= sys->el.number;  sysIndex= i; }
255
 
    sys= (GeSystem *)sys->el.next;
256
 
  } while (sys!=drawing->systems);
257
 
  GdSetSystem(sysIndex);
258
 
  if (nMax<0) {
259
 
    if (sysIndex<1) currentSy= 0;
260
 
    currentEl= 0;
261
 
  } else {
262
 
    GdElement *el= currentSy? currentSy->elements : drawing->elements;
263
 
    if (el) {
264
 
      currentEl= el->prev;
265
 
      currentEl->ops->GetProps(currentEl);
266
 
    } else {
267
 
      currentEl= 0;
268
 
    }
269
 
  }
270
 
  currentCn= -1;
271
 
 
272
 
  return 0;
273
 
}
274
 
 
275
 
int GdClear(Drauing *drawing)
276
 
{
277
 
  if (!drawing) drawing= currentDr;
278
 
  if (!drawing) return 1;
279
 
  drawing->cleared= 1;
280
 
  return 0;
281
 
}
282
 
 
283
 
static void ClearDrawing(Drauing *drawing)
284
 
{
285
 
  GeSystem *sys, *sys0= drawing->systems;
286
 
  int nSystems= 0;
287
 
  if ((sys= sys0)) do {
288
 
    Gd_KillRing(sys->elements);
289
 
    sys->elements= 0;
290
 
    sys->rescan= 0;
291
 
    sys->unscanned= -1;
292
 
    sys->el.number= -1;
293
 
    sys= (GeSystem *)sys->el.next;
294
 
    nSystems++;
295
 
  } while (sys!=sys0);
296
 
  Gd_KillRing(drawing->elements);
297
 
  drawing->elements= 0;
298
 
  drawing->nElements= 0;
299
 
  drawing->nSystems= nSystems;
300
 
  drawing->cleared= 2;
301
 
 
302
 
  if (drawing==currentDr) {
303
 
    currentSy= drawing->systems; /* as after GdSetDrawing */
304
 
    currentEl= 0;
305
 
    currentCn= -1;
306
 
  }
307
 
 
308
 
  /* Must detatch drawing from all engines, since even inactive ones
309
 
     need to know that the drawing has been erased.  */
310
 
  GdDetach(drawing, (Engine *)0);
311
 
}
312
 
 
313
 
/* ------------------------------------------------------------------------ */
314
 
 
315
 
/* The GIST display list is called a "drawing".  Any number of drawings
316
 
   may exist, but only one may be active at a time.
317
 
 
318
 
   The entire drawing is rendered on all active engines by calling
319
 
   GdDraw(0).  The drawing sequence is preceded by GpClear(0, CONDITIONALLY).
320
 
 
321
 
   GdDraw(-1) is like GdDraw(0) except the drawing is damaged to force
322
 
   all data to be rescanned as well.
323
 
 
324
 
   GdDraw(1) draws only the changes since the previous GdDraw.  Changes can
325
 
   be either destructive or non-destructive:
326
 
 
327
 
     If the engine->damage box is set, then some operation has
328
 
     damaged that part of the drawing since the prior GdDraw
329
 
     (such as changing a line style or plot limits).  The damaged
330
 
     section is cleared, then the display list is traversed, redrawing
331
 
     all elements which may intersect the damaged box, clipped to
332
 
     the damaged box.
333
 
 
334
 
     Then, any elements which were added since the prior GdDraw
335
 
     (and which caused no damage like a change in limits) are
336
 
     drawn as non-destructive updates.
337
 
 
338
 
 */
339
 
 
340
 
static void Damage(GeSystem *sys, GdElement *el)
341
 
{
342
 
  GpBox *box, adjustBox;
343
 
  if (!currentDr) return;
344
 
  if (!el) {
345
 
    if (!sys) return;
346
 
    /* If no element, damage the entire coordinate system, ticks and all */
347
 
    box= &sys->el.box;
348
 
  } else if (sys) {
349
 
    /* If element is in a coordinate system, damage the whole viewport */
350
 
    box= &sys->trans.viewport;
351
 
  } else {
352
 
    /* Elements not in a coordinate system already have NDC box--
353
 
       but may need to adjust it to allow for projecting junk.  */
354
 
    el->ops->Margin(el, &adjustBox);
355
 
    adjustBox.xmin+= el->box.xmin;
356
 
    adjustBox.xmax+= el->box.xmax;
357
 
    adjustBox.ymin+= el->box.ymin;
358
 
    adjustBox.ymax+= el->box.ymax;
359
 
    box= &adjustBox;
360
 
  }
361
 
  if (currentDr->damaged) {
362
 
    GpSwallow(&currentDr->damage, box);
363
 
  } else {
364
 
    currentDr->damage= *box;
365
 
    currentDr->damaged= 1;
366
 
  }
367
 
}
368
 
 
369
 
static void SquareAdjust(GpReal *umin, GpReal *umax,
370
 
                         GpReal dv, int doMin, int doMax)
371
 
{
372
 
  if (doMin) {
373
 
    if (doMax) umax[0]= 0.5*(umin[0]+umax[0]+dv);
374
 
    umin[0]= umax[0]-dv;
375
 
  } else if (doMax) {
376
 
    umax[0]= umin[0]+dv;
377
 
  }
378
 
}
379
 
 
380
 
static void NiceAdjust(GpReal *umin, GpReal *umax, int isLog, int isMin)
381
 
{
382
 
  GpReal un= *umin,   ux= *umax;
383
 
  GpReal unit,   du= ux-un;
384
 
  int base, power, reverted= 0;
385
 
  if (isLog) {
386
 
    if (du <= LOG2) {
387
 
      /* revert to linear scale */
388
 
      un= exp10(un);
389
 
      ux= exp10(ux);
390
 
      du= ux-un;
391
 
      reverted= 1;
392
 
    } else if (du>6.0 && isMin) {
393
 
      un= ux-6.0;
394
 
      du= 6.0;
395
 
    }
396
 
  }
397
 
  unit= GpNiceUnit(du/3.0, &base, &power);
398
 
  if (!isLog || reverted || unit>0.75) {
399
 
    un= unit*floor(un/unit);
400
 
    ux= unit*ceil(ux/unit);
401
 
    if (reverted) {
402
 
      un= log10(un);
403
 
      ux= log10(ux);
404
 
    }
405
 
  } else {
406
 
    /* subdecade log scale (sigh), use 2, 5, or 10 */
407
 
    GpReal dn= floor(un+0.0001),   dx= ceil(ux-0.0001);
408
 
    if (un<dn+(LOG2-0.0001)) un= dn;
409
 
    else if (un<dn+(0.9999-LOG2)) un= dn+LOG2;
410
 
    else un= dn+(1.0-LOG2);
411
 
    if (ux>dx-(LOG2+0.0001)) ux= dx;
412
 
    else if (ux>dx-(1.0001-LOG2)) ux= dx-LOG2;
413
 
    else ux= ux-(1.0-LOG2);
414
 
  }
415
 
  *umin= un;
416
 
  *umax= ux;
417
 
}
418
 
 
419
 
static void EqAdjust(GpReal *umin, GpReal *umax)
420
 
{
421
 
  GpReal nudge= *umin>0.0? 0.001*(*umin) : -0.001*(*umin);
422
 
  if (nudge==0.0) nudge= 1.0e-6;
423
 
  *umin-= nudge;
424
 
  *umax+= nudge;
425
 
}
426
 
 
427
 
static void EmptyAdjust(GpReal *umin, GpReal *umax, int doMin, int doMax)
428
 
{
429
 
  if (doMin) {
430
 
    if (doMax) { *umin= -1.0e-6; *umax= +1.0e-6; }
431
 
    else if (*umax>0.0) *umin= 0.999*(*umax);
432
 
    else if (*umax<0.0) *umin= 1.001*(*umax);
433
 
    else *umin= -1.0e-6;
434
 
  } else if (doMax) {
435
 
    if (*umin>0.0) *umax= 1.001*(*umin);
436
 
    else if (*umin<0.0) *umax= 0.999*(*umin);
437
 
    else *umax= +1.0e-6;
438
 
  } else if ((*umin)==(*umax)) {
439
 
    EqAdjust(umin, umax);
440
 
  }
441
 
}
442
 
 
443
 
static void EqualAdjust(GpReal *umin, GpReal *umax, int doMin, int doMax)
444
 
{
445
 
  if (doMin && doMax) EqAdjust(umin, umax);
446
 
  else EmptyAdjust(umin, umax, doMin, doMax);
447
 
}
448
 
 
449
 
int GdScan(GeSystem *sys)
450
 
{
451
 
  int flags= sys->flags;
452
 
  GpBox limits, tmp, *w= &sys->trans.window;
453
 
  GpReal xmin= w->xmin, xmax= w->xmax, ymin= w->ymin, ymax= w->ymax;
454
 
  int swapx, swapy;
455
 
  GdElement *el, *el0= sys->elements;
456
 
  int begin, damaged, first;
457
 
 
458
 
  /* Handle case of no curves (if, e.g., all elements removed) */
459
 
  if (!el0) {
460
 
    EmptyAdjust(&w->xmin, &w->xmax, flags&D_XMIN, flags&D_XMAX);
461
 
    EmptyAdjust(&w->ymin, &w->ymax, flags&D_YMIN, flags&D_YMAX);
462
 
    return 0;
463
 
  }
464
 
 
465
 
  /* Assure that limits are ordered even if window is not */
466
 
  swapx= (xmin > xmax) && !(flags&(D_XMIN|D_XMAX));
467
 
  swapy= (ymin > ymax) && !(flags&(D_YMIN|D_YMAX));
468
 
  if (!swapx) { limits.xmin= xmin;  limits.xmax= xmax; }
469
 
  else { limits.xmin= xmax;  limits.xmax= xmin; }
470
 
  if (!swapy) { limits.ymin= ymin;  limits.ymax= ymax; }
471
 
  else { limits.ymin= ymax;  limits.ymax= ymin; }
472
 
  tmp= limits;
473
 
 
474
 
  el= el0;
475
 
  begin= sys->rescan? -1 : sys->unscanned;
476
 
 
477
 
  /* Scan limits for each element */
478
 
  damaged= 0;
479
 
  first= 1;
480
 
  do {
481
 
    if (!el->hidden) {
482
 
      if (el->number>=begin) {
483
 
        /* Scan ensures log values present, sets box, scans xy values */
484
 
        if (el->ops->Scan(el, flags, &tmp)) return 1; /* mem failure */
485
 
        if (first) {
486
 
          /* first non-hidden element gives first cut at limits */
487
 
          limits= tmp;
488
 
          damaged= 1;
489
 
        } else {
490
 
          /* subsequent elements may cause limits to be adjusted */
491
 
          if (tmp.xmin<=tmp.xmax) {
492
 
            if (tmp.xmin<limits.xmin) limits.xmin= tmp.xmin;
493
 
            if (tmp.xmax>limits.xmax) limits.xmax= tmp.xmax;
494
 
          }
495
 
          if (tmp.ymin<=tmp.ymax) {
496
 
            if (tmp.ymin<limits.ymin) limits.ymin= tmp.ymin;
497
 
            if (tmp.ymax>limits.ymax) limits.ymax= tmp.ymax;
498
 
          }
499
 
        }
500
 
      }
501
 
      first= 0;
502
 
    }
503
 
    el= el->next;
504
 
  } while (el!=el0);
505
 
 
506
 
  /* #1- adjust if min==max */
507
 
  if (limits.xmin==limits.xmax)
508
 
    EqualAdjust(&limits.xmin, &limits.xmax, flags&D_XMIN, flags&D_XMAX);
509
 
  if (limits.ymin==limits.ymax)
510
 
    EqualAdjust(&limits.ymin, &limits.ymax, flags&D_XMIN, flags&D_XMAX);
511
 
 
512
 
  /* #2- adjust if log axis and minimum was SAFELOG(0) */
513
 
  if ((flags & D_LOGX) && (flags & D_XMIN) && limits.xmin==SAFELOG0
514
 
      && limits.xmax>SAFELOG0+10.0) limits.xmin= limits.xmax-10.0;
515
 
  if ((flags & D_LOGY) && (flags & D_YMIN) && limits.ymin==SAFELOG0
516
 
      && limits.ymax>SAFELOG0+10.0) limits.ymin= limits.ymax-10.0;
517
 
 
518
 
  /* #3- adjust if square limits specified and not semi-logarithmic */
519
 
  if ((flags & D_SQUARE) &&
520
 
      !(((flags&D_LOGX)!=0) ^ ((flags&D_LOGY)!=0))) {
521
 
    /* (Square axes don't make sense for semi-log scales) */
522
 
    GpReal dx= limits.xmax-limits.xmin;
523
 
    GpReal dy= limits.ymax-limits.ymin;
524
 
    GpReal dydx= (sys->trans.viewport.ymax-sys->trans.viewport.ymin)/
525
 
                 (sys->trans.viewport.xmax-sys->trans.viewport.xmin);
526
 
    /* Adjust y if either (1) dx>dy, or (2) x limits are both fixed
527
 
       (NB- SquareAdjust is a noop if both limits fixed) */
528
 
    if ((dx*dydx>dy && (flags&(D_YMIN|D_YMAX))) ||
529
 
        !(flags&(D_XMIN|D_XMAX)))
530
 
      SquareAdjust(&limits.ymin, &limits.ymax, dx*dydx,
531
 
                   flags&D_YMIN, flags&D_YMAX);
532
 
    else /* adjust x */
533
 
      SquareAdjust(&limits.xmin, &limits.xmax, dy/dydx,
534
 
                   flags&D_XMIN, flags&D_XMAX);
535
 
  }
536
 
 
537
 
  /* #4- adjust if nice limits specified */
538
 
  if (flags & D_NICE) {
539
 
    NiceAdjust(&limits.xmin, &limits.xmax, flags&D_LOGX, flags&D_XMIN);
540
 
    NiceAdjust(&limits.ymin, &limits.ymax, flags&D_LOGY, flags&D_YMIN);
541
 
  }
542
 
 
543
 
  if (swapx) {
544
 
    GpReal tmp= limits.xmin;  limits.xmin= limits.xmax;  limits.xmax= tmp;
545
 
  }
546
 
  if (swapy) {
547
 
    GpReal tmp= limits.ymin;  limits.ymin= limits.ymax;  limits.ymax= tmp;
548
 
  }
549
 
  if (damaged || limits.xmin!=xmin || limits.xmax!=xmax ||
550
 
      limits.ymin!=ymin || limits.ymax!=ymax)
551
 
    Damage(sys, (GdElement *)0);
552
 
  w->xmin= limits.xmin;
553
 
  w->xmax= limits.xmax;
554
 
  w->ymin= limits.ymin;
555
 
  w->ymax= limits.ymax;
556
 
 
557
 
  sys->rescan= 0;
558
 
  sys->unscanned= -1;
559
 
 
560
 
  return 0;
561
 
}
562
 
 
563
 
int Gd_DrawRing(void *elv, int xIsLog, int yIsLog, GeSystem *sys, int t)
564
 
{
565
 
  GdElement *el0, *el= elv;
566
 
  GpBox adjustBox, *box;
567
 
  int value= 0, drawIt= t;
568
 
  if ((el0= el)) {
569
 
    do {
570
 
      if (!t) {
571
 
        if (!sys) {
572
 
          el->ops->Margin(el, &adjustBox);
573
 
          adjustBox.xmin+= el->box.xmin;
574
 
          adjustBox.xmax+= el->box.xmax;
575
 
          adjustBox.ymin+= el->box.ymin;
576
 
          adjustBox.ymax+= el->box.ymax;
577
 
          box= &adjustBox;
578
 
        } else {
579
 
          box= &sys->trans.viewport;
580
 
        }
581
 
        drawIt= GdBeginEl(box, el->number);
582
 
      }
583
 
      if (drawIt) value|= el->ops->Draw(el, xIsLog, yIsLog);
584
 
      el= el->next;
585
 
    } while (el!=el0);
586
 
  }
587
 
  return value;
588
 
}
589
 
 
590
 
static GpTransform unitTrans= { {0., 2., 0., 2.}, {0., 2., 0., 2.} };
591
 
 
592
 
int GdDraw(int changesOnly)
593
 
{
594
 
  int value= 0;
595
 
  GpBox *damage;
596
 
  int systemCounter;
597
 
  int rescan= 0;
598
 
 
599
 
  if (!currentDr) return 1;
600
 
 
601
 
  if (changesOnly==-1) {
602
 
    rescan= 1;
603
 
    changesOnly= 0;
604
 
  }
605
 
 
606
 
  /* Take care of conditional clear */
607
 
  if (currentDr->cleared==1) {
608
 
    if (changesOnly) return 0;
609
 
    else ClearDrawing(currentDr);
610
 
  }
611
 
  if (!changesOnly || currentDr->cleared) {
612
 
    GpClear(0, CONDITIONALLY);
613
 
    currentDr->cleared= 0;
614
 
  }
615
 
 
616
 
  /* Check if any coordinate systems need to be rescanned */
617
 
  if (currentDr->systems) {
618
 
    int changed;
619
 
    GeSystem *sys, *sys0;
620
 
    sys= sys0= currentDr->systems;
621
 
    do {
622
 
      if (rescan) sys->rescan= 1;
623
 
      changed= (sys->rescan || sys->unscanned>=0);
624
 
      if (changed) changesOnly= 0;
625
 
      if (changed && GdScan(sys)) return 1;  /* memory manager failure */
626
 
      sys= (GeSystem *)sys->el.next;
627
 
    } while (sys!=sys0);
628
 
  }
629
 
 
630
 
  /* Give engines a chance to prepare for a drawing */
631
 
  if (currentDr->damaged) {
632
 
    damage= &currentDr->damage;
633
 
    currentDr->damaged= 0;
634
 
  } else {
635
 
    damage= 0;
636
 
  }
637
 
  /* GdBeginDr returns 1 if any active engine has been cleared or
638
 
     partially cleared.  */
639
 
  if (!GdBeginDr(currentDr, damage, currentDr->landscape) && changesOnly)
640
 
    return 0;
641
 
 
642
 
  /* Do coordinate systems */
643
 
  if (currentDr->systems) {
644
 
    GeSystem *sys, *sys0;
645
 
    sys= sys0= currentDr->systems;
646
 
    systemCounter= 0;
647
 
    do {
648
 
      value|= SystemDraw(sys, systemCounter, 0);
649
 
      systemCounter++;
650
 
      sys= (GeSystem *)sys->el.next;
651
 
    } while (sys!=sys0);
652
 
  }
653
 
 
654
 
  /* Do elements outside of coordinate systems */
655
 
  GpSetTrans(&unitTrans);
656
 
  gistClip= 0;
657
 
  value|= Gd_DrawRing(currentDr->elements, 0, 0, (GeSystem *)0, 0);
658
 
 
659
 
  /* Give engines a chance to clean up after a drawing */
660
 
  GdEndDr();
661
 
 
662
 
  return value;
663
 
}
664
 
 
665
 
/* ------------------------------------------------------------------------ */
666
 
/* Legend routines */
667
 
 
668
 
int GdLegendBox(int which, GpReal x, GpReal y, GpReal dx, GpReal dy,
669
 
                const GpTextAttribs *t, int nchars, int nlines, int nwrap)
670
 
{
671
 
  GeLegendBox *lbox;
672
 
  if (!currentDr || nchars<0) return 1;
673
 
  lbox= currentDr->legends;
674
 
  if (which) lbox++;
675
 
  lbox->x= x;     lbox->y= y;
676
 
  lbox->dx= dx;   lbox->dy= dy;
677
 
  lbox->textStyle= *t;
678
 
  lbox->nchars= nchars;
679
 
  lbox->nlines= nlines;
680
 
  lbox->nwrap= nwrap;
681
 
  return 0;
682
 
}
683
 
 
684
 
static char *legendText= 0;
685
 
static long lenLegends, maxLegends= 0;
686
 
 
687
 
static int nRemaining, curWrap;
688
 
static char *curLegend;
689
 
static int curMarker= 0;
690
 
 
691
 
static int doingContours, levelCurve, nLevels;
692
 
static GdElement *curElement, *cur0Element, *drElements, *curCon, *cur0Con;
693
 
static GeSystem *curSystem, *cur0System;
694
 
static GpReal *levelValue;
695
 
static GeLines **levelGroup;
696
 
static char levelLegend[32];
697
 
 
698
 
static void InitLegends(int contours, GeSystem *systems, GdElement *elements,
699
 
                        int size)
700
 
{
701
 
  doingContours= levelCurve= contours;
702
 
  if (doingContours) curCon= 0;
703
 
  curElement= 0;
704
 
  curSystem= cur0System= systems;
705
 
  drElements= elements;
706
 
  curLegend= 0;
707
 
  curMarker= 0;
708
 
  nRemaining= 0;
709
 
 
710
 
  if (size>maxLegends) {
711
 
    if (legendText) p_free(legendText);
712
 
    legendText= p_malloc((long)size);
713
 
  }
714
 
}
715
 
 
716
 
static void NextContours(void)
717
 
{
718
 
  if (!levelCurve) {
719
 
    /* Set up for the ring of level curves */
720
 
    GeContours *con= (GeContours *)curCon;
721
 
    nLevels= con->nLevels;
722
 
    levelValue= con->levels;
723
 
    levelGroup= con->groups;
724
 
    levelCurve= 1;
725
 
    if (levelGroup) {
726
 
      while (nLevels && !levelGroup[0]) {
727
 
        levelValue++;
728
 
        levelGroup++;
729
 
        nLevels--;
730
 
      }
731
 
    } else {
732
 
      nLevels= 0;
733
 
    }
734
 
    if (nLevels>0) curElement= (GdElement *)levelGroup[0];
735
 
    else curElement= 0;
736
 
    return;
737
 
  }
738
 
 
739
 
  levelCurve= 0;
740
 
  curElement= 0;
741
 
  if (curCon) {
742
 
    curCon= curCon->next;
743
 
    if (curCon==cur0Con) curCon= 0;
744
 
  }
745
 
  for (;;) {
746
 
    if (curCon) {
747
 
      do {
748
 
        if (curCon->ops->type==E_CONTOURS && !curCon->hidden) {
749
 
          /* Set up for contour element itself-- terminates immediately */
750
 
          curElement= curCon;
751
 
          cur0Element= curElement->next;
752
 
          return;
753
 
        }
754
 
        curCon= curCon->next;
755
 
      } while (curCon!=cur0Con);
756
 
    }
757
 
 
758
 
    if (curSystem) {
759
 
      curCon= cur0Con= curSystem->elements;
760
 
      curSystem= (GeSystem *)curSystem->el.next;
761
 
      if (curSystem==cur0System) curSystem= 0;
762
 
    } else if (drElements) {
763
 
      curCon= cur0Con= drElements;
764
 
      drElements= 0;
765
 
    } else {
766
 
      break;
767
 
    }
768
 
  }
769
 
}
770
 
 
771
 
static int NextRing(void)
772
 
{
773
 
  if (doingContours) {
774
 
    NextContours();
775
 
    if (!curElement) return 0;
776
 
  } else if (curSystem) {
777
 
    curElement= cur0Element= curSystem->elements;
778
 
    curSystem= (GeSystem *)curSystem->el.next;
779
 
    if (curSystem==cur0System) curSystem= 0;
780
 
  } else if (drElements) {
781
 
    curElement= cur0Element= drElements;
782
 
    drElements= 0;
783
 
  } else {
784
 
    return 0;
785
 
  }
786
 
  return 1;
787
 
}
788
 
 
789
 
static int specialMarks[5]= { '.', '+', '*', 'o', 'x' };
790
 
 
791
 
static int NextLegend(void)
792
 
{
793
 
  curLegend= 0;
794
 
  curMarker= 0;
795
 
  do {
796
 
    while (curElement) {
797
 
      if (!curElement->hidden) {
798
 
        int type= curElement->ops->type;
799
 
        if (curElement->legend) curLegend= curElement->legend;
800
 
        else if (levelCurve) {
801
 
          /* automatically generate level curve legend if not supplied */
802
 
          curLegend= levelLegend;
803
 
          sprintf(curLegend, "\001: %.4g", *levelValue);
804
 
        }
805
 
        if (curLegend) {
806
 
          nRemaining= strlen(curLegend);
807
 
          curWrap= 0;
808
 
          if ((type==E_LINES || type==E_CONTOURS) && curLegend[0]=='\001') {
809
 
            /* insert marker into E_LINES legend if so directed */
810
 
            curMarker= type==E_LINES? ((GeLines *)curElement)->m.type :
811
 
            ((GeContours *)curElement)->m.type;
812
 
            if (curMarker>=1 && curMarker<=5)
813
 
              curMarker= specialMarks[curMarker-1];
814
 
            else if (curMarker<' ' || curMarker>='\177')
815
 
              curMarker= ' ';
816
 
          }
817
 
        }
818
 
      }
819
 
      if (levelCurve) {
820
 
        do {
821
 
          levelValue++;
822
 
          levelGroup++;
823
 
          nLevels--;
824
 
        } while (nLevels && !levelGroup[0]);
825
 
        if (nLevels>0) curElement= (GdElement *)levelGroup[0];
826
 
        else curElement= 0;
827
 
      } else {
828
 
        curElement= curElement->next;
829
 
        if (curElement==cur0Element) curElement= 0;
830
 
      }
831
 
      if (curLegend) return 1;
832
 
    }
833
 
  } while (NextRing());
834
 
  return 0;
835
 
}
836
 
 
837
 
static int BuildLegends(int more, int contours, GeSystem *systems,
838
 
                        GdElement *elements, GeLegendBox *lbox)
839
 
{
840
 
  int firstLine= 1;
841
 
  int nlines= lbox->nlines;
842
 
  int nchars= lbox->nchars;
843
 
  int nwrap= lbox->nwrap;
844
 
  int nc;
845
 
 
846
 
  lenLegends= 0;
847
 
  if (!more) {
848
 
    if (nlines<=0 || nchars<=0) return 0;
849
 
    InitLegends(contours, systems, elements, (nchars+1)*nlines);
850
 
    if (!legendText) return 0;
851
 
  }
852
 
 
853
 
  for ( ; ; nlines--) {
854
 
    if (!curLegend && !NextLegend()) { more= 0;   break; }
855
 
    if (nlines<=0) { more= !more;   break; }
856
 
    if (firstLine) firstLine= 0;
857
 
    else legendText[lenLegends++]= '\n';
858
 
    nc= nRemaining>nchars? nchars : nRemaining;
859
 
    strncpy(legendText+lenLegends, curLegend, nc);
860
 
    if (curMarker) {
861
 
      legendText[lenLegends]= (char)curMarker;
862
 
      curMarker= 0;
863
 
    }
864
 
    lenLegends+= nc;
865
 
    nRemaining-= nc;
866
 
    if (nRemaining>0 && curWrap++<nwrap) curLegend+= nc;
867
 
    else { curLegend= 0; curMarker= 0; }
868
 
  }
869
 
 
870
 
  legendText[lenLegends]= '\0';
871
 
  return more;
872
 
}
873
 
 
874
 
int GdDrawLegends(Engine *engine)
875
 
{
876
 
  GpReal x, y;
877
 
  int type, more;
878
 
  GeLegendBox *lbox;
879
 
  if (!currentDr) return 1;
880
 
 
881
 
  if (engine) GpPreempt(engine);
882
 
 
883
 
  for (type=0 ; type<2 ; type++) {
884
 
    lbox= &currentDr->legends[type];
885
 
    x= lbox->x;
886
 
    y= lbox->y;
887
 
    gistA.t= lbox->textStyle;
888
 
    GpSetTrans(&unitTrans);
889
 
    gistClip= 0;
890
 
    if (lbox->nlines <= 0) continue;
891
 
    for (more=0 ; ; ) {
892
 
      more= BuildLegends(more, type, currentDr->systems, currentDr->elements,
893
 
                         lbox);
894
 
      if (!legendText) {
895
 
        /* memory error */
896
 
        if (engine) GpPreempt(0);
897
 
        return 1;
898
 
      }
899
 
      if (lenLegends>0) GpText(x, y, legendText);
900
 
      if (!more || (lbox->dx==0.0 && lbox->dy==0.0)) break;
901
 
      x+= lbox->dx;
902
 
      y+= lbox->dy;
903
 
    }
904
 
  }
905
 
 
906
 
  if (engine) GpPreempt(0);
907
 
  return 0;
908
 
}
909
 
 
910
 
/* ------------------------------------------------------------------------ */
911
 
/* Utility routines */
912
 
 
913
 
static int MemoryError(void)
914
 
{
915
 
  if (currentDr)
916
 
    strcpy(gistError, "memory manager failed in Gd function");
917
 
  else
918
 
    strcpy(gistError, "currentDr not set in Gd function");
919
 
  return -1;
920
 
}
921
 
 
922
 
static void *Copy1(const void *orig, long size)
923
 
{
924
 
  void *px;
925
 
  if (size<=0) return 0;
926
 
  px= p_malloc(size);
927
 
  if (!px) MemoryError();
928
 
  else if (orig) memcpy(px, orig, size);
929
 
  return px;
930
 
}
931
 
 
932
 
static void *Copy2(void *x1, const void *orig1, const void *orig2, long size)
933
 
{
934
 
  void *x2, **x1p= (void **)x1;
935
 
  *x1p= Copy1(orig1, size);
936
 
  if (!*x1p) return 0;
937
 
  x2= Copy1(orig2, size);
938
 
  if (!x2) { p_free(*x1p);  *x1p= 0; }
939
 
  return x2;
940
 
}
941
 
 
942
 
void Gd_ScanZ(long n, const GpReal *z, GpReal *zmin, GpReal *zmax)
943
 
{
944
 
  long i;
945
 
  GpReal zn, zx;
946
 
  zn= zx= z[0];
947
 
  for (i=1 ; i<n ; i++) {
948
 
    if (z[i]<zn) zn= z[i];
949
 
    else if (z[i]>zx) zx= z[i];
950
 
  }
951
 
  *zmin= zn;
952
 
  *zmax= zx;
953
 
}
954
 
 
955
 
static void ScanXY(long n, const GpReal *x, const GpReal *y, GpBox *extrema)
956
 
{
957
 
  Gd_ScanZ(n, x, &extrema->xmin, &extrema->xmax);
958
 
  Gd_ScanZ(n, y, &extrema->ymin, &extrema->ymax);
959
 
}
960
 
 
961
 
void GeAddElement(int type, GdElement *element)
962
 
{
963
 
  GdElement *old;
964
 
  Drauing *drawing= currentDr;
965
 
  GeSystem *sys;
966
 
 
967
 
  if (drawing->cleared==1) ClearDrawing(drawing);
968
 
  sys= currentSy;
969
 
 
970
 
  old= sys? sys->elements : drawing->elements;
971
 
  if (!old) {  /* this is first element */
972
 
    if (sys) sys->elements= element;
973
 
    else drawing->elements= element;
974
 
    element->prev= element->next= element;
975
 
  } else {     /* insert element at end of ring */
976
 
    element->prev= old->prev;
977
 
    element->next= old;
978
 
    old->prev= element->prev->next= element;
979
 
  }
980
 
  element->ops= opTables + type;
981
 
  element->hidden= gistD.hidden;
982
 
  if (gistD.legend) {
983
 
    element->legend= Copy1(gistD.legend, strlen(gistD.legend)+1);
984
 
    /* sigh. ignore memory error here */
985
 
  } else {
986
 
    element->legend= 0;
987
 
  }
988
 
  element->number= drawing->nElements++;
989
 
  /* System nust always have number of its largest element for
990
 
     GdBeginSy to work properly */
991
 
  if (sys) sys->el.number= element->number;
992
 
  else Damage((GeSystem *)0, element);
993
 
}
994
 
 
995
 
void Gd_NextMeshBlock(long *ii, long *jj, long len, long iMax,
996
 
                      int *reg, int region)
997
 
{   /* Find next contiguous run of mesh points in given region */
998
 
  long i= *ii;
999
 
  long j= *jj;
1000
 
  if (region==0) {
1001
 
    for (j=i ; j<len ; j++)
1002
 
      if (reg[j] || reg[j+1] || reg[j+iMax] || reg[j+iMax+1]) break;
1003
 
    i= j;
1004
 
    for (j=i+1 ; j<len ; j++)
1005
 
      if (!reg[j] && !reg[j+1] && !reg[j+iMax] && !reg[j+iMax+1]) break;
1006
 
  } else {
1007
 
    for (j=i ; j<len ; j++)
1008
 
      if (reg[j]==region || reg[j+1]==region ||
1009
 
          reg[j+iMax]==region || reg[j+iMax+1]==region) break;
1010
 
    i= j;
1011
 
    for (j=i+1 ; j<len ; j++)
1012
 
      if (reg[j]!=region && reg[j+1]!=region &&
1013
 
          reg[j+iMax]!=region && reg[j+iMax+1]!=region) break;
1014
 
  }
1015
 
  *ii= i;
1016
 
  *jj= j;
1017
 
}
1018
 
 
1019
 
long GeGetMesh(int noCopy, GaQuadMesh *meshin, int region, void *vMeshEl)
1020
 
{
1021
 
  GeMesh *meshEl= vMeshEl;
1022
 
  GaQuadMesh *mesh= &meshEl->mesh;
1023
 
  GpBox *linBox= &meshEl->linBox;
1024
 
  long iMax, jMax, i, j, len;
1025
 
  int *reg;
1026
 
 
1027
 
  if (currentDr->cleared==1) ClearDrawing(currentDr);
1028
 
 
1029
 
  /* retrieve mesh shape from meshin */
1030
 
  mesh->iMax= iMax= meshin->iMax;
1031
 
  mesh->jMax= jMax= meshin->jMax;
1032
 
  len= iMax*jMax;
1033
 
 
1034
 
  mesh->reg= 0;       /* set up for possible error return */
1035
 
  mesh->triangle= 0;  /* only needed by GdContours, so handled there */
1036
 
 
1037
 
  meshEl->xlog= meshEl->ylog= 0;
1038
 
  meshEl->region= region;
1039
 
 
1040
 
  meshEl->noCopy= noCopy & (NOCOPY_MESH|NOCOPY_COLORS|NOCOPY_UV|NOCOPY_Z);
1041
 
  if (noCopy&NOCOPY_MESH) {
1042
 
    /* Just copy pointers to mesh arrays -- NOCOPY also means not
1043
 
       to free the pointer later */
1044
 
    mesh->x= meshin->x;
1045
 
    mesh->y= meshin->y;
1046
 
  } else {
1047
 
    /* Copy the mesh arrays themselves */
1048
 
    mesh->y= Copy2(&mesh->x, meshin->x, meshin->y, sizeof(GpReal)*len);
1049
 
    if (!mesh->y) { p_free(vMeshEl);  return 0; }
1050
 
  }
1051
 
 
1052
 
  if ((noCopy&NOCOPY_MESH) && meshin->reg) {
1053
 
    mesh->reg= reg= meshin->reg;
1054
 
    meshEl->noCopy|= NOCOPY_REG;
1055
 
  } else {
1056
 
    mesh->reg= reg= Copy1(meshin->reg, sizeof(int)*(len+iMax+1));
1057
 
    if (!reg) { Gd_KillMeshXY(vMeshEl);  p_free(vMeshEl);  return 0; }
1058
 
  }
1059
 
 
1060
 
  /* Be sure region array is legal */
1061
 
  for (i=0 ; i<iMax ; i++) reg[i]= 0;
1062
 
  if (!meshin->reg) for (i=iMax ; i<len ; i++) reg[i]= 1;
1063
 
  for (i=len ; i<len+iMax+1 ; i++) reg[i]= 0;
1064
 
  for (i=0 ; i<len ; i+=iMax) reg[i]= 0;
1065
 
 
1066
 
  /* Scan mesh for extreme values */
1067
 
  if (meshin->reg) {
1068
 
    GpBox box;
1069
 
    int first= 1;
1070
 
 
1071
 
    /* Use ScanXY on the longest contiguous run(s) of points */
1072
 
    for (i=0 ; i<len ; ) {
1073
 
      Gd_NextMeshBlock(&i, &j, len, iMax, reg, region);
1074
 
      if (i>=len) break;
1075
 
      ScanXY(j-i, mesh->x+i, mesh->y+i, &box);
1076
 
      if (first) { *linBox= box;  first= 0; }
1077
 
      else GpSwallow(linBox, &box);
1078
 
      i= j+1;
1079
 
    }
1080
 
    if (first)
1081
 
      linBox->xmin= linBox->xmax= linBox->ymin= linBox->ymax= 0.0;
1082
 
 
1083
 
  } else {
1084
 
    ScanXY(len, mesh->x, mesh->y, linBox);
1085
 
  }
1086
 
  if (!currentSy) meshEl->el.box= *linBox;  /* for GeAddElement */
1087
 
 
1088
 
  /* copy mesh properties to gistD */
1089
 
  Gd_MeshXYGet(vMeshEl);
1090
 
 
1091
 
  return len;
1092
 
}
1093
 
 
1094
 
void GeMarkForScan(GdElement *el, GpBox *linBox)
1095
 
{
1096
 
  if (currentSy) {
1097
 
    if (currentSy->unscanned<0) currentSy->unscanned= el->number;
1098
 
  } else {
1099
 
    el->box= *linBox;
1100
 
  }
1101
 
}
1102
 
 
1103
 
static int AutoMarker(GaLineAttribs *dl, int number)
1104
 
{
1105
 
  int p;
1106
 
  p= (number+3)%4;
1107
 
  if (number>=26) number%= 26;
1108
 
  dl->mPhase= 0.25*(0.5+p)*dl->mSpace;
1109
 
  dl->rPhase= 0.25*(0.5+p)*dl->rSpace;
1110
 
  return 'A'+number;
1111
 
}
1112
 
 
1113
 
/* ------------------------------------------------------------------------ */
1114
 
/* Constructors for drawing elements are public routines declared in gist.h */
1115
 
 
1116
 
int GdLines(long n, const GpReal *px, const GpReal *py)
1117
 
{
1118
 
  GeLines *el;
1119
 
  if (n<=0) return -1;
1120
 
  el= currentDr? p_malloc(sizeof(GeLines)) : 0;
1121
 
  if (!el) return MemoryError();
1122
 
  el->xlog= el->ylog= 0;
1123
 
 
1124
 
  /* make private copies of x and y arrays */
1125
 
  el->y= Copy2(&el->x, px, py, sizeof(GpReal)*n);
1126
 
  if (!el->y) { p_free(el);  return -1; }
1127
 
  el->n= n;
1128
 
 
1129
 
  /* scan for min and max of x and y arrays */
1130
 
  ScanXY(n, px, py, &el->linBox);
1131
 
  if (!currentSy) el->el.box= el->linBox;  /* for GeAddElement */
1132
 
 
1133
 
  /* copy relevant attributes from gistA
1134
 
     -- This must be done BEFORE GeAddElement, since the damage
1135
 
        calculation depends on the Margins! */
1136
 
  el->l= gistA.l;
1137
 
  el->dl= gistA.dl;
1138
 
  el->m= gistA.m;
1139
 
 
1140
 
  /* set base class members */
1141
 
  GeAddElement(E_LINES, &el->el);
1142
 
  if (gistA.m.type==0) el->m.type= AutoMarker(&el->dl, el->el.number);
1143
 
 
1144
 
  /* current box not set, mark as unscanned if in system */
1145
 
  GeMarkForScan(&el->el, &el->linBox);
1146
 
 
1147
 
  /* copy properties to gistD */
1148
 
  gistD.n= n;
1149
 
  gistD.x= el->x;
1150
 
  gistD.y= el->y;
1151
 
 
1152
 
  return el->el.number;
1153
 
}
1154
 
 
1155
 
int GdDisjoint(long n, const GpReal *px, const GpReal *py,
1156
 
               const GpReal *qx, const GpReal *qy)
1157
 
{
1158
 
  GeDisjoint *el;
1159
 
  GpBox box;
1160
 
  if (n<=0) return -1;
1161
 
  el= currentDr? p_malloc(sizeof(GeDisjoint)) : 0;
1162
 
  if (!el) return MemoryError();
1163
 
  el->el.next= el->el.prev= 0;
1164
 
  el->xlog= el->ylog= el->xqlog= el->yqlog= 0;
1165
 
 
1166
 
  /* make private copies of x, y, xq, yq arrays */
1167
 
  el->y= Copy2(&el->x, px, py, sizeof(GpReal)*n);
1168
 
  if (!el->y) { p_free(el);  return -1; }
1169
 
  el->yq= Copy2(&el->xq, qx, qy, sizeof(GpReal)*n);
1170
 
  if (!el->yq) { DisjointKill(el);  return -1; }
1171
 
  el->n= n;
1172
 
 
1173
 
  /* scan for min and max of x and y arrays */
1174
 
  ScanXY(n, px, py, &box);
1175
 
  ScanXY(n, qx, qy, &el->linBox);
1176
 
  GpSwallow(&el->linBox, &box);
1177
 
  if (!currentSy) el->el.box= el->linBox;  /* for GeAddElement */
1178
 
 
1179
 
  /* copy relevant attributes from gistA
1180
 
     -- This must be done BEFORE GeAddElement, since the damage
1181
 
        calculation depends on the Margins! */
1182
 
  el->l= gistA.l;
1183
 
 
1184
 
  /* set base class members */
1185
 
  GeAddElement(E_DISJOINT, &el->el);
1186
 
 
1187
 
  /* current box not set, mark as unscanned if in system */
1188
 
  GeMarkForScan(&el->el, &el->linBox);
1189
 
 
1190
 
  /* copy properties to gistD */
1191
 
  gistD.n= n;
1192
 
  gistD.x= el->x;
1193
 
  gistD.y= el->y;
1194
 
  gistD.xq= el->xq;
1195
 
  gistD.yq= el->yq;
1196
 
 
1197
 
  return el->el.number;
1198
 
}
1199
 
 
1200
 
int GdText(GpReal x0, GpReal y0, const char *text, int toSys)
1201
 
{
1202
 
  GeText *el= currentDr? p_malloc(sizeof(GeText)) : 0;
1203
 
  GeSystem *sys= currentSy;
1204
 
  if (!el) return MemoryError();
1205
 
 
1206
 
  /* make private copy of text string */
1207
 
  el->text= Copy1(text, strlen(text)+1);
1208
 
  if (!el->text) { p_free(el);  return -1; }
1209
 
  el->x0= x0;
1210
 
  el->y0= y0;
1211
 
 
1212
 
  /* Without some sort of common font metric, there is no way to
1213
 
     know the box associated with text.  Even with such a metric,
1214
 
     the box would have to change with the coordinate transform,
1215
 
     unlike any other element.  For now, punt.  */
1216
 
  el->el.box.xmin= el->el.box.xmax= x0;
1217
 
  el->el.box.ymin= el->el.box.ymax= y0;
1218
 
 
1219
 
  /* copy relevant attributes from gistA
1220
 
     -- This must be done BEFORE GeAddElement, since the damage
1221
 
        calculation depends on the Margins! */
1222
 
  el->t= gistA.t;
1223
 
 
1224
 
  /* set base class members */
1225
 
  if (currentDr->cleared==1) ClearDrawing(currentDr); /* else currentSy */
1226
 
  if (!toSys) currentSy= 0;                      /* can be clobbered... */
1227
 
  GeAddElement(E_TEXT, &el->el);
1228
 
  if (currentSy && currentSy->unscanned<0)
1229
 
    currentSy->unscanned= el->el.number;
1230
 
  if (!toSys) currentSy= sys;
1231
 
 
1232
 
  /* copy properties to gistD */
1233
 
  gistD.x0= el->x0;
1234
 
  gistD.y0= el->y0;
1235
 
  gistD.text= el->text;
1236
 
 
1237
 
  return el->el.number;
1238
 
}
1239
 
 
1240
 
int GdCells(GpReal px, GpReal py, GpReal qx, GpReal qy,
1241
 
            long width, long height, long nColumns, const GpColor *colors)
1242
 
{
1243
 
  GpReal x[2], y[2];
1244
 
  GpBox linBox;
1245
 
  long ncells= width*height;
1246
 
  long len= sizeof(GpColor)*ncells;
1247
 
  GeCells *el= currentDr? p_malloc(sizeof(GeCells)) : 0;
1248
 
  if (!el) return MemoryError();
1249
 
 
1250
 
  /* make private copy of colors array */
1251
 
  el->rgb = gistA.rgb;
1252
 
  if (gistA.rgb) len *= 3;
1253
 
  gistA.rgb = 0;
1254
 
  el->colors= p_malloc(len);
1255
 
  if (!el->colors) { p_free(el); return MemoryError(); }
1256
 
  el->px= x[0]= px;
1257
 
  el->py= y[0]= py;
1258
 
  el->qx= x[1]= qx;
1259
 
  el->qy= y[1]= qy;
1260
 
  el->width= width;
1261
 
  el->height= height;
1262
 
  if (nColumns==width) {
1263
 
    memcpy(el->colors, colors, len);
1264
 
  } else {
1265
 
    GpColor *newcols= el->colors;
1266
 
    long i, rowSize= sizeof(GpColor)*width;
1267
 
    for (i=0 ; i<height ; i++) {
1268
 
      memcpy(newcols, colors, rowSize);
1269
 
      newcols+= width;
1270
 
      colors+= nColumns;
1271
 
    }
1272
 
  }
1273
 
  ScanXY(2L, x, y, &linBox);
1274
 
  if (!currentSy) el->el.box= linBox;  /* for GeAddElement */
1275
 
 
1276
 
  /* set base class members */
1277
 
  GeAddElement(E_CELLS, &el->el);
1278
 
 
1279
 
  /* current box not set, mark as unscanned if in system */
1280
 
  GeMarkForScan(&el->el, &linBox);
1281
 
 
1282
 
  /* copy properties to gistD */
1283
 
  gistD.px= el->px;
1284
 
  gistD.py= el->py;
1285
 
  gistD.qx= el->qx;
1286
 
  gistD.qy= el->qy;
1287
 
  gistD.width= el->width;
1288
 
  gistD.height= el->height;
1289
 
  gistD.colors= el->colors;
1290
 
 
1291
 
  return el->el.number;
1292
 
}
1293
 
 
1294
 
int GdFill(long n, const GpColor *colors, const GpReal *px,
1295
 
           const GpReal *py, const long *pn)
1296
 
{
1297
 
  GePolys *el;
1298
 
  long i, ntot;
1299
 
  if (n<=0) return -1;
1300
 
  el= currentDr? p_malloc(sizeof(GePolys)) : 0;
1301
 
  if (!el) return MemoryError();
1302
 
  el->xlog= el->ylog= 0;
1303
 
 
1304
 
  /* make private copy of colors array */
1305
 
  if (colors) {
1306
 
    long ncol = (gistA.rgb? 3*n : n);
1307
 
    el->rgb = gistA.rgb;
1308
 
    el->colors= p_malloc(ncol);
1309
 
    if (!el->colors) { p_free(el); return MemoryError(); }
1310
 
    memcpy(el->colors, colors, ncol);
1311
 
  } else {
1312
 
    el->rgb = 0;
1313
 
    el->colors= 0;
1314
 
  }
1315
 
  gistA.rgb = 0;
1316
 
 
1317
 
  /* make private copy of lengths array */
1318
 
  el->pn= p_malloc(sizeof(long)*n);
1319
 
  if (!el->pn) { p_free(el->colors); p_free(el); return MemoryError(); }
1320
 
  for (ntot=i=0 ; i<n ; i++) {
1321
 
    el->pn[i]= pn[i];
1322
 
    ntot+= pn[i];
1323
 
  }
1324
 
 
1325
 
  /* make private copies of x and y arrays */
1326
 
  el->y= Copy2(&el->x, px, py, sizeof(GpReal)*ntot);
1327
 
  if (!el->y) { p_free(el->pn); p_free(el->colors); p_free(el);  return -1; }
1328
 
  el->n= n;
1329
 
 
1330
 
  /* scan for min and max of x and y arrays */
1331
 
  if (n<2 || pn[1]>1) ScanXY(ntot, px, py, &el->linBox);
1332
 
  else ScanXY(ntot-pn[0], px+pn[0], py+pn[0], &el->linBox);
1333
 
  if (!currentSy) el->el.box= el->linBox;  /* for GeAddElement */
1334
 
 
1335
 
  /* copy relevant attributes from gistA
1336
 
     -- This must be done BEFORE GeAddElement, since the damage
1337
 
        calculation depends on the Margins! */
1338
 
  el->e= gistA.e;  /* for edges */
1339
 
 
1340
 
  /* set base class members */
1341
 
  GeAddElement(E_POLYS, &el->el);
1342
 
 
1343
 
  /* current box not set, mark as unscanned if in system */
1344
 
  GeMarkForScan(&el->el, &el->linBox);
1345
 
 
1346
 
  /* copy properties to gistD */
1347
 
  gistD.n= n;
1348
 
  gistD.x= el->x;
1349
 
  gistD.y= el->y;
1350
 
  gistD.pn= el->pn;
1351
 
  gistD.colors= el->colors;
1352
 
 
1353
 
  return el->el.number;
1354
 
}
1355
 
 
1356
 
int GdMesh(int noCopy, GaQuadMesh *mesh, int region, int boundary,
1357
 
           int inhibit)
1358
 
{
1359
 
  long len;
1360
 
  GeMesh *el= currentDr? p_malloc(sizeof(GeMesh)) : 0;
1361
 
  if (!el) return MemoryError();
1362
 
  el->el.next= el->el.prev= 0;
1363
 
 
1364
 
  /* get mesh */
1365
 
  len= GeGetMesh(noCopy, mesh, region, el);
1366
 
  if (!len) return -1;
1367
 
  el->boundary= boundary;
1368
 
  el->inhibit= inhibit;
1369
 
 
1370
 
  /* copy relevant attributes from gistA
1371
 
     -- This must be done BEFORE GeAddElement, since the damage
1372
 
        calculation depends on the Margins! */
1373
 
  el->l= gistA.l;
1374
 
 
1375
 
  /* set base class members */
1376
 
  GeAddElement(E_MESH, &el->el);
1377
 
 
1378
 
  /* current box not set, mark as unscanned if in system */
1379
 
  GeMarkForScan(&el->el, &el->linBox);
1380
 
 
1381
 
  /* copy properties to gistD */
1382
 
  gistD.boundary= el->boundary;
1383
 
  gistD.inhibit= el->inhibit;
1384
 
 
1385
 
  return el->el.number;
1386
 
}
1387
 
 
1388
 
int GdFillMesh(int noCopy, GaQuadMesh *mesh, int region,
1389
 
               GpColor *colors, long nColumns)
1390
 
{
1391
 
  long len;
1392
 
  GeFill *el= currentDr? p_malloc(sizeof(GeFill)) : 0;
1393
 
  if (!el) return MemoryError();
1394
 
  el->el.next= el->el.prev= 0;
1395
 
 
1396
 
  /* get mesh */
1397
 
  len= GeGetMesh(noCopy, mesh, region, el);
1398
 
  if (!len) return -1;
1399
 
 
1400
 
  /* make private copy of colors array */
1401
 
  el->rgb = gistA.rgb;
1402
 
  if (noCopy&NOCOPY_COLORS || !colors) {
1403
 
    el->colors= colors;
1404
 
  } else {
1405
 
    long iMax1= mesh->iMax-1;
1406
 
    long len1= len - mesh->jMax - iMax1;
1407
 
    int rgb = gistA.rgb;
1408
 
    if (rgb) len1 *= 3;
1409
 
    el->colors= Copy1(nColumns==iMax1?colors:0, sizeof(GpColor)*len1);
1410
 
    if (!el->colors) { FilledKill(el);  return -1; }
1411
 
    if (nColumns!=iMax1) {
1412
 
      long i, j=0, k=0;
1413
 
      for (i=0 ; i<len1 ; i++) {
1414
 
        if (rgb) {
1415
 
          el->colors[i++]= colors[3*(j+k)];
1416
 
          el->colors[i++]= colors[3*(j+k)+1];
1417
 
          el->colors[i]= colors[3*(j+k)+2];
1418
 
        } else {
1419
 
          el->colors[i]= colors[j+k];
1420
 
        }
1421
 
        j++;
1422
 
        if (j==iMax1) { k+= nColumns; j= 0; }
1423
 
      }
1424
 
      nColumns= iMax1;
1425
 
    }
1426
 
  }
1427
 
  gistA.rgb = 0;
1428
 
  el->nColumns= nColumns;
1429
 
 
1430
 
  /* copy relevant attributes from gistA
1431
 
     -- This must be done BEFORE GeAddElement, since the damage
1432
 
        calculation depends on the Margins! */
1433
 
  el->e= gistA.e;  /* for edges */
1434
 
 
1435
 
  /* set base class members */
1436
 
  GeAddElement(E_FILLED, &el->el);
1437
 
 
1438
 
  /* current box not set, mark as unscanned if in system */
1439
 
  GeMarkForScan(&el->el, &el->linBox);
1440
 
 
1441
 
  /* copy properties to gistD */
1442
 
  gistD.nColumns= nColumns;
1443
 
  gistD.colors= el->colors;
1444
 
 
1445
 
  return el->el.number;
1446
 
}
1447
 
 
1448
 
int GdVectors(int noCopy, GaQuadMesh *mesh, int region,
1449
 
              GpReal *u, GpReal *v, GpReal scale)
1450
 
{
1451
 
  long len;
1452
 
  GeVectors *el= currentDr? p_malloc(sizeof(GeVectors)) : 0;
1453
 
  if (!el) return MemoryError();
1454
 
  el->el.next= el->el.prev= 0;
1455
 
 
1456
 
  /* get mesh */
1457
 
  len= GeGetMesh(noCopy, mesh, region, el);
1458
 
  if (!len) return -1;
1459
 
 
1460
 
  /* make private copy of (u,v) arrays */
1461
 
  if (noCopy&NOCOPY_UV) {
1462
 
    el->u= u;
1463
 
    el->v= v;
1464
 
  } else {
1465
 
    el->v= Copy2(&el->u, u, v, sizeof(GpReal)*len);
1466
 
    if (!el->v) { VectorsKill(el);  return -1; }
1467
 
  }
1468
 
  el->scale= scale;
1469
 
 
1470
 
  /* copy relevant attributes from gistA
1471
 
     -- This must be done BEFORE GeAddElement, since the damage
1472
 
        calculation depends on the Margins! */
1473
 
  el->l= gistA.l;
1474
 
  el->f= gistA.f;
1475
 
  el->vect= gistA.vect;
1476
 
 
1477
 
  /* set base class members */
1478
 
  GeAddElement(E_VECTORS, &el->el);
1479
 
 
1480
 
  /* current box not set, mark as unscanned if in system */
1481
 
  GeMarkForScan(&el->el, &el->linBox);
1482
 
 
1483
 
  /* copy properties to gistD */
1484
 
  gistD.u= el->u;
1485
 
  gistD.v= el->v;
1486
 
  gistD.scale= el->scale;
1487
 
 
1488
 
  return el->el.number;
1489
 
}
1490
 
 
1491
 
int Gd_MakeContours(GeContours *con)
1492
 
{
1493
 
  long n;
1494
 
  GpReal dphase, *px, *py;
1495
 
  int i;
1496
 
  GeLines *group;
1497
 
  GeLines *el, *prev;
1498
 
  int marker;
1499
 
 
1500
 
  /* Generic properties copied to all contours (m.type reset below)  */
1501
 
  gistA.l= con->l;
1502
 
  gistA.dl= con->dl;
1503
 
  gistA.m= con->m;
1504
 
  marker= gistA.m.type>32? gistA.m.type : 'A';
1505
 
  dphase= 0.25*con->dl.mSpace;
1506
 
 
1507
 
  for (i=0 ; i<con->nLevels ; i++) con->groups[i]= 0;
1508
 
 
1509
 
  for (i=0 ; i<con->nLevels ; i++) {
1510
 
    gistA.m.type= marker++;
1511
 
    if (marker=='Z'+1 || marker=='z'+1) marker= 'A';
1512
 
    group= prev= 0;
1513
 
    if (GaContourInit(&con->mesh, con->region, con->z, con->levels[i])) {
1514
 
      while (GaContour(&n, &px, &py, &gistA.dl.closed)) {
1515
 
        el= currentDr? p_malloc(sizeof(GeLines)) : 0;
1516
 
        if (!el) return MemoryError();
1517
 
 
1518
 
        /* make private copies of x and y arrays */
1519
 
        el->y= Copy2(&el->x, px, py, sizeof(GpReal)*n);
1520
 
        if (!el->y) { p_free(el);  return -1; }
1521
 
        el->n= n;
1522
 
        el->xlog= el->ylog= 0;
1523
 
 
1524
 
        /* scan for min and max of x and y arrays */
1525
 
        ScanXY(n, px, py, &el->linBox);
1526
 
        if (!currentSy) el->el.box= el->linBox;  /* for GeAddElement */
1527
 
 
1528
 
        el->el.ops= opTables + E_LINES;
1529
 
        el->el.hidden= 0;
1530
 
        el->el.legend= 0;
1531
 
        el->el.box= el->linBox;
1532
 
 
1533
 
        /* GeContour number always matches number of largest element
1534
 
           for GdBeginSy to work properly */
1535
 
        el->el.number= con->el.number= currentDr->nElements++;
1536
 
 
1537
 
        if (prev) {
1538
 
          prev->el.next= group->el.prev= &el->el;
1539
 
          el->el.prev= &prev->el;
1540
 
          el->el.next= &group->el;
1541
 
        } else {
1542
 
          con->groups[i]= group= el;
1543
 
          el->el.next= el->el.prev= &el->el;
1544
 
        }
1545
 
        prev= el;
1546
 
 
1547
 
        el->l= gistA.l;
1548
 
        el->dl= gistA.dl;
1549
 
        el->m= gistA.m;
1550
 
 
1551
 
        gistA.dl.mPhase+= dphase;
1552
 
        if (gistA.dl.mPhase>gistA.dl.mSpace)
1553
 
          gistA.dl.mPhase-= gistA.dl.mSpace;
1554
 
      }
1555
 
    }
1556
 
  }
1557
 
 
1558
 
  return 0;
1559
 
}
1560
 
 
1561
 
int GdContours(int noCopy, GaQuadMesh *mesh, int region,
1562
 
               GpReal *z, const GpReal *levels, int nLevels)
1563
 
{
1564
 
  long len;
1565
 
  GeContours *el= currentDr? p_malloc(sizeof(GeContours)) : 0;
1566
 
  if (!el) return MemoryError();
1567
 
  el->el.next= el->el.prev= 0;
1568
 
  el->z= el->levels= 0;
1569
 
  el->groups= 0;
1570
 
 
1571
 
  /* get mesh */
1572
 
  len= GeGetMesh(noCopy, mesh, region, el);
1573
 
  if (!len) return -1;
1574
 
 
1575
 
  /* make private copy of z and levels arrays */
1576
 
  if (noCopy&NOCOPY_Z) {
1577
 
    el->z= z;
1578
 
  } else {
1579
 
    el->z= Copy1(z, sizeof(GpReal)*len);
1580
 
    if (!el->z) { ContoursKill(el);  return -1; }
1581
 
  }
1582
 
 
1583
 
  /* create triangle array now if necessary */
1584
 
  if (noCopy&NOCOPY_MESH && mesh->triangle) {
1585
 
    el->mesh.triangle= mesh->triangle;
1586
 
    el->noCopy|= NOCOPY_TRI;
1587
 
    gistD.noCopy|= NOCOPY_TRI;
1588
 
  } else {
1589
 
    el->mesh.triangle= Copy1(mesh->triangle, sizeof(short)*len);
1590
 
    if (!el->mesh.triangle) { ContoursKill(el);  return -1; }
1591
 
  }
1592
 
 
1593
 
  /* copy relevant attributes from gistA
1594
 
     -- This must be done BEFORE GeAddElement, since the damage
1595
 
        calculation depends on the Margins! */
1596
 
  el->l= gistA.l;
1597
 
  el->dl= gistA.dl;
1598
 
  el->m= gistA.m;
1599
 
 
1600
 
  /* set base class members */
1601
 
  GeAddElement(E_CONTOURS, &el->el);
1602
 
  if (gistA.m.type==0) el->m.type= AutoMarker(&el->dl, el->el.number);
1603
 
 
1604
 
  el->nLevels= nLevels;
1605
 
  if (nLevels>0) {
1606
 
    el->levels= Copy1(levels, sizeof(GpReal)*nLevels);
1607
 
    if (!el->levels) { ContoursKill(el);  return -1; }
1608
 
    el->groups= (GeLines **)p_malloc(sizeof(GeLines *)*nLevels);
1609
 
    if (!el->groups || Gd_MakeContours(el)) { ContoursKill(el);  return -1; }
1610
 
  } else {
1611
 
    nLevels= 0;
1612
 
    el->levels= 0;
1613
 
    el->groups= 0;
1614
 
  }
1615
 
 
1616
 
  /* current box not set, mark as unscanned if in system */
1617
 
  GeMarkForScan(&el->el, &el->linBox);
1618
 
 
1619
 
  /* copy properties to gistD */
1620
 
  gistD.z= el->z;
1621
 
  gistD.nLevels= el->nLevels;
1622
 
  gistD.levels= el->levels;
1623
 
 
1624
 
  return el->el.number;
1625
 
}
1626
 
 
1627
 
/* ------------------------------------------------------------------------ */
1628
 
 
1629
 
static void GuessBox(GpBox *box, GpBox *viewport, GaTickStyle *ticks)
1630
 
{
1631
 
  GpReal dxmin= 0.0, xmin= viewport->xmin;
1632
 
  GpReal dxmax= 0.0, xmax= viewport->xmax;
1633
 
  GpReal dymin= 0.0, ymin= viewport->ymin;
1634
 
  GpReal dymax= 0.0, ymax= viewport->ymax;
1635
 
  int vf= ticks->vert.flags;
1636
 
  int hf= ticks->horiz.flags;
1637
 
  GpReal vlen= ((((vf&TICK_IN)&&(vf&TICK_OUT))||(vf&TICK_C))? 0.5 : 1.0) *
1638
 
    ticks->vert.tickLen[0];
1639
 
  GpReal hlen= ((((vf&TICK_IN)&&(vf&TICK_OUT))||(vf&TICK_C))? 0.5 : 1.0) *
1640
 
    ticks->horiz.tickLen[0];
1641
 
  GpReal cy= ticks->horiz.textStyle.height;
1642
 
  GpReal cx= ticks->vert.textStyle.height*0.6;  /* guess at char width */
1643
 
  GpReal hx= cy*0.6;                            /* guess at char width */
1644
 
  GpBox overflow;
1645
 
 
1646
 
  /* Note-- extra 0.4 for nudged log decades (see DrawXLabels, tick.c) */
1647
 
  cx*= ticks->vert.nDigits+2.4;         /* largest width of y label */
1648
 
  hx*= 0.5*(ticks->horiz.nDigits+2.4);  /* maximum distance x label
1649
 
                                           can project past xmin, xmax */
1650
 
 
1651
 
  if (((vf&TICK_L)&&(vf&TICK_OUT)) || (vf&TICK_C))
1652
 
    dxmin= ticks->vert.tickOff+vlen;
1653
 
  if (((vf&TICK_U)&&(vf&TICK_OUT)) || (vf&TICK_C))
1654
 
    dxmax= ticks->vert.tickOff+vlen;
1655
 
  if (((hf&TICK_L)&&(hf&TICK_OUT)) || (hf&TICK_C))
1656
 
    dymin= ticks->horiz.tickOff+hlen;
1657
 
  if (((hf&TICK_U)&&(hf&TICK_OUT)) || (hf&TICK_C))
1658
 
    dymax= ticks->horiz.tickOff+hlen;
1659
 
 
1660
 
  if (vf & LABEL_L) xmin-= ticks->vert.labelOff+cx;
1661
 
  else if ((hf&(LABEL_L|LABEL_U)) && hx>dxmin) xmin-= hx;
1662
 
  else xmin-= dxmin;
1663
 
  if (vf & LABEL_U) xmax+= ticks->vert.labelOff+cx;
1664
 
  else if ((hf&(LABEL_L|LABEL_U)) && hx>dxmax) xmax+= hx;
1665
 
  else xmax+= dxmax;
1666
 
 
1667
 
  if (hf & LABEL_L) ymin-= ticks->horiz.labelOff+2.0*cy;
1668
 
  else if ((vf&(LABEL_L|LABEL_U)) && 0.5*cy>dymin) ymin-= 0.5*cy;
1669
 
  else ymin-= dymin;
1670
 
  if (hf & LABEL_U) xmax+= ticks->horiz.labelOff+2.0*cy;
1671
 
  else if ((vf&(LABEL_L|LABEL_U)) && 0.5*cy>dymax) ymax+= 0.5*cy;
1672
 
  else ymax+= dymax;
1673
 
 
1674
 
  if (vf & (TICK_L|TICK_U)) {
1675
 
    xmin-= 0.5*ticks->vert.tickStyle.width*DEFAULT_LINE_WIDTH;
1676
 
    xmax+= 0.5*ticks->vert.tickStyle.width*DEFAULT_LINE_WIDTH;
1677
 
  }
1678
 
  if (hf & (TICK_L|TICK_U)) {
1679
 
    ymin-= 0.5*ticks->horiz.tickStyle.width*DEFAULT_LINE_WIDTH;
1680
 
    ymax+= 0.5*ticks->horiz.tickStyle.width*DEFAULT_LINE_WIDTH;
1681
 
  }
1682
 
 
1683
 
  box->xmin= xmin;
1684
 
  box->xmax= xmax;
1685
 
  box->ymin= ymin;
1686
 
  box->ymax= ymax;
1687
 
 
1688
 
  /* Finally, swallow overflow boxes, assuming 22 characters max */
1689
 
  overflow.xmin= ticks->horiz.xOver;
1690
 
  overflow.ymin= ticks->horiz.yOver-ticks->horiz.textStyle.height*0.2;
1691
 
  overflow.xmax= overflow.xmin+ticks->horiz.textStyle.height*(0.6*22.0);
1692
 
  overflow.ymax= overflow.ymin+ticks->horiz.textStyle.height;
1693
 
  GpSwallow(box, &overflow);
1694
 
  overflow.xmin= ticks->vert.xOver;
1695
 
  overflow.ymin= ticks->vert.yOver-ticks->vert.textStyle.height*0.2;
1696
 
  overflow.xmax= overflow.xmin+ticks->vert.textStyle.height*(0.6*22.0);
1697
 
  overflow.ymax= overflow.ymin+ticks->vert.textStyle.height;
1698
 
  GpSwallow(box, &overflow);
1699
 
}
1700
 
 
1701
 
int GdNewSystem(GpBox *viewport, GaTickStyle *ticks)
1702
 
{
1703
 
  GeSystem *sys;
1704
 
  int sysIndex;
1705
 
 
1706
 
  if (!currentDr) return -1;
1707
 
 
1708
 
  /* Adding a new system clears the drawing */
1709
 
  if (currentDr->cleared!=2) ClearDrawing(currentDr);
1710
 
  sysIndex= currentDr->nSystems+1;
1711
 
 
1712
 
  sys= p_malloc(sizeof(GeSystem));
1713
 
  if (!sys) return -1;
1714
 
  sys->el.ops= opTables + E_SYSTEM;
1715
 
  if (gistD.legend) {
1716
 
    sys->el.legend= Copy1(gistD.legend, strlen(gistD.legend)+1);
1717
 
    if (!sys->el.legend) { p_free(sys);  return -1; }
1718
 
  } else sys->el.legend= 0;
1719
 
  sys->el.hidden= gistD.hidden;
1720
 
 
1721
 
  if (sysIndex>1) {
1722
 
    GdElement *prev= currentDr->systems->el.prev;
1723
 
    prev->next= &sys->el;
1724
 
    sys->el.prev= prev;
1725
 
    sys->el.next= &currentDr->systems->el;
1726
 
    currentDr->systems->el.prev= &sys->el;
1727
 
  } else {
1728
 
    sys->el.prev= sys->el.next= &sys->el;
1729
 
    currentDr->systems= sys;
1730
 
  }
1731
 
  sys->el.number= -1;
1732
 
  currentDr->nSystems++;
1733
 
  sys->rescan= 0;
1734
 
  sys->unscanned= -1;
1735
 
 
1736
 
  GuessBox(&sys->el.box, viewport, ticks);
1737
 
 
1738
 
  if (viewport->xmin<viewport->xmax) {
1739
 
    sys->trans.viewport.xmin= viewport->xmin;
1740
 
    sys->trans.viewport.xmax= viewport->xmax;
1741
 
  } else {
1742
 
    sys->trans.viewport.xmin= viewport->xmax;
1743
 
    sys->trans.viewport.xmax= viewport->xmin;
1744
 
  }
1745
 
  if (viewport->ymin<viewport->ymax) {
1746
 
    sys->trans.viewport.ymin= viewport->ymin;
1747
 
    sys->trans.viewport.ymax= viewport->ymax;
1748
 
  } else {
1749
 
    sys->trans.viewport.ymin= viewport->ymax;
1750
 
    sys->trans.viewport.ymax= viewport->ymin;
1751
 
  }
1752
 
  sys->trans.window.xmin= sys->trans.window.ymin= 0.0;
1753
 
  sys->trans.window.xmax= sys->trans.window.ymax= 1.0;
1754
 
  sys->ticks= *ticks;
1755
 
  sys->flags= D_XMIN | D_XMAX | D_YMIN | D_YMAX;
1756
 
  sys->elements= 0;
1757
 
  sys->savedWindow.xmin= sys->savedWindow.ymin= 0.0;
1758
 
  sys->savedWindow.xmax= sys->savedWindow.ymax= 1.0;
1759
 
  sys->savedFlags= D_XMIN | D_XMAX | D_YMIN | D_YMAX;
1760
 
 
1761
 
  sys->xtick= sys->ytick= 0;
1762
 
  sys->xlabel= sys->ylabel= 0;
1763
 
 
1764
 
  GdSetSystem(sysIndex);
1765
 
  return sysIndex;
1766
 
}
1767
 
 
1768
 
int GdGetSystem(void)
1769
 
{
1770
 
  GdElement *sys, *sys0;
1771
 
  int sysIndex= 0;
1772
 
  if (!currentDr) return -1;
1773
 
  if (!currentDr->systems || !currentSy) return 0;
1774
 
 
1775
 
  /* ClearDrawing sets currentSy-- must not be pending */
1776
 
  if (currentDr->cleared==1) ClearDrawing(currentDr);
1777
 
 
1778
 
  sys= sys0= (GdElement *)currentDr->systems;
1779
 
  for (sysIndex=1 ; sys!=&currentSy->el ; sysIndex++) {
1780
 
    sys= sys->next;
1781
 
    if (sys==sys0) return -2;
1782
 
  }
1783
 
 
1784
 
  return sysIndex;
1785
 
}
1786
 
 
1787
 
int GdSetSystem(int sysIndex)
1788
 
{
1789
 
  GeSystem *sys;
1790
 
  GdElement *sys0;
1791
 
  if (!currentDr || !currentDr->systems) return E_NONE;
1792
 
 
1793
 
  /* ClearDrawing sets currentSy-- must not be pending */
1794
 
  if (currentDr->cleared==1) ClearDrawing(currentDr);
1795
 
 
1796
 
  currentEl= 0;
1797
 
  currentCn= -1;
1798
 
  if (sysIndex<1) {  /* Set current system to none */
1799
 
    currentSy= 0;
1800
 
    gistD.trans.viewport.xmin= gistD.trans.viewport.xmax=
1801
 
      gistD.trans.viewport.ymin= gistD.trans.viewport.ymax= 0.0;
1802
 
    gistD.flags= 0;
1803
 
    return E_NONE;
1804
 
  }
1805
 
 
1806
 
  sys= currentDr->systems;
1807
 
  sys0= &sys->el;
1808
 
  while (--sysIndex && sys->el.next!=sys0)
1809
 
    sys= (GeSystem *)sys->el.next;
1810
 
  if (sysIndex>0) return E_NONE;
1811
 
 
1812
 
  currentSy= sys;
1813
 
  gistD.hidden= sys->el.hidden;
1814
 
  gistD.legend= sys->el.legend;
1815
 
  gistD.ticks= sys->ticks;
1816
 
  gistD.trans.viewport= sys->trans.viewport;
1817
 
  if (GdGetLimits()) {
1818
 
    SystemKill(sys);
1819
 
    return E_NONE;
1820
 
  }
1821
 
  return E_SYSTEM;
1822
 
}
1823
 
 
1824
 
int GdSetElement(int elIndex)
1825
 
{
1826
 
  GdElement *el, *el0;
1827
 
  if (!currentDr) return E_NONE;
1828
 
 
1829
 
  el= currentSy? currentSy->elements : currentDr->elements;
1830
 
 
1831
 
  if (elIndex<0 || !el) {   /* set current element to none */
1832
 
    currentEl= 0;
1833
 
    currentCn= -1;
1834
 
    return E_NONE;
1835
 
  }
1836
 
 
1837
 
  el0= el;
1838
 
  while (elIndex-- && el->next!=el0) el= el->next;
1839
 
  if (elIndex>=0) return E_NONE;
1840
 
 
1841
 
  currentEl= el;
1842
 
  currentCn= -1;
1843
 
  return el->ops->GetProps(el);
1844
 
}
1845
 
 
1846
 
static GdElement *NextConCurve(GdElement *el)
1847
 
{
1848
 
  GeContours *con= (GeContours *)currentEl;
1849
 
  GdElement *el0= &con->groups[currentCn]->el;
1850
 
  if (!el) el= el0;
1851
 
  else if (el->next==el0) el= 0;
1852
 
  else el= el->next;
1853
 
  return el;
1854
 
}
1855
 
 
1856
 
int GdSetContour(int levIndex)
1857
 
{
1858
 
  GeContours *con;
1859
 
  GdElement *el;
1860
 
  if (!currentDr || !currentEl || currentEl->ops->type!=E_CONTOURS)
1861
 
    return E_NONE;
1862
 
  con= (GeContours *)currentEl;
1863
 
  if (levIndex>=con->nLevels) return E_NONE;
1864
 
  if (levIndex<0) {
1865
 
    currentCn= -1;
1866
 
    return E_NONE;
1867
 
  }
1868
 
  currentCn= levIndex;
1869
 
  el= NextConCurve((GdElement *)0);
1870
 
  if (el) LinesGet(el);
1871
 
  else ContoursGet(con);
1872
 
  return E_LINES;
1873
 
}
1874
 
 
1875
 
static int GeFindIndex(int id, GeSystem *sys)
1876
 
{
1877
 
  int elIndex;
1878
 
  GdElement *el, *el0;
1879
 
  if (!currentDr) return -1;
1880
 
 
1881
 
  el= sys? sys->elements : currentDr->elements;
1882
 
  if (!el) return -1;
1883
 
 
1884
 
  el0= el;
1885
 
  elIndex= 0;
1886
 
  while (el->number != id) {
1887
 
    if (el->next==el0) return -1;
1888
 
    el= el->next;
1889
 
    elIndex++;
1890
 
  }
1891
 
 
1892
 
  return elIndex;
1893
 
}
1894
 
 
1895
 
int GdFindIndex(int id)
1896
 
{
1897
 
  return GeFindIndex(id, currentSy);
1898
 
}
1899
 
 
1900
 
int GdFindSystem(int id)
1901
 
{
1902
 
  int sysIndex;
1903
 
  GeSystem *sys;
1904
 
  GdElement *sys0;
1905
 
  if (!currentDr) return -1;
1906
 
 
1907
 
  if (GeFindIndex(id, 0)>=0) return 0;
1908
 
  sys= currentDr->systems;
1909
 
  if (!sys) return -1;
1910
 
  sys0= &sys->el;
1911
 
  sysIndex= 1;
1912
 
  while (GeFindIndex(id, sys)<0) {
1913
 
    if (sys->el.next==sys0) return -1;
1914
 
    sys= (GeSystem *)sys->el.next;
1915
 
    sysIndex++;
1916
 
  }
1917
 
  return sysIndex;
1918
 
}
1919
 
 
1920
 
int GdAltTick(GaAltTicks *xtick, GaAltLabel *xlabel,
1921
 
              GaAltTicks *ytick, GaAltLabel *ylabel)
1922
 
{
1923
 
  if (!currentDr || !currentSy) return 1;
1924
 
  if (xtick) currentSy->xtick= xtick;
1925
 
  if (ytick) currentSy->ytick= ytick;
1926
 
  if (xlabel) currentSy->xlabel= xlabel;
1927
 
  if (ylabel) currentSy->ylabel= ylabel;
1928
 
  return 0;
1929
 
}
1930
 
 
1931
 
/* ------------------------------------------------------------------------ */
1932
 
 
1933
 
int GdEdit(int xyzChanged)
1934
 
{
1935
 
  GdElement *el= currentEl;
1936
 
  if (!currentDr || !el) return 1;
1937
 
 
1938
 
  /* Changing linestyles or most other simple changes may incur damage
1939
 
     in a way that is very difficult to anticipate, hence, must call
1940
 
     Damage here.  On the other hand, the elements need to be rescanned
1941
 
     only if CHANGE_XY or CHANGE_Z has been set, so only set rescan
1942
 
     in this case.  If only linestyles and such have been changed, GdScan
1943
 
     will not call Damage again, although if they have it will-- hence, if
1944
 
     you are changing both coordinates and linestyles, there is no way to
1945
 
     avoid "double damage".  */
1946
 
  Damage(currentSy, el);
1947
 
  if (currentSy && xyzChanged) currentSy->rescan= 1;
1948
 
 
1949
 
  if (currentCn>=0) {
1950
 
    el= NextConCurve((GdElement *)0);
1951
 
    if (el) {
1952
 
      /* legend only changes on first piece of contour */
1953
 
      el->legend= gistD.legend;
1954
 
      Gd_LinesSubSet(el);
1955
 
      /* other line properties propagate to all contour pieces
1956
 
         -- but NEVER attempt to change the (x,y) values */
1957
 
      while ((el= NextConCurve(el))) Gd_LinesSubSet(el);
1958
 
    }
1959
 
    return 0;
1960
 
  }
1961
 
  return el->ops->SetProps(el, xyzChanged);
1962
 
}
1963
 
 
1964
 
int GdRemove(void)
1965
 
{
1966
 
  GdElement *el= currentEl;
1967
 
  if (!currentDr || !el || currentCn>=0) return 1;
1968
 
 
1969
 
  /* Damage alert must take place here-- unfortunately, if this remove
1970
 
     changes extreme values, a second call to Damage will be made in
1971
 
     GdScan.  Hopefully, GdRemove is a rare enough operation that this
1972
 
     inefficiency is negligible.  */
1973
 
  Damage(currentSy, el);
1974
 
 
1975
 
  if (currentSy) {
1976
 
    GdElement *prev= el->prev;
1977
 
    if (el==prev) {
1978
 
      currentSy->unscanned= -1;
1979
 
      currentSy->rescan= 0;
1980
 
      currentSy->el.number= -1;
1981
 
    } else {
1982
 
      if (el->number==currentSy->unscanned) {
1983
 
        if (el->next != currentSy->elements)
1984
 
          currentSy->unscanned= el->next->number;
1985
 
        else currentSy->unscanned= -1;
1986
 
      }
1987
 
      if (el->number<currentSy->unscanned && !el->hidden)
1988
 
        currentSy->rescan= 1;
1989
 
      if (el->number==currentSy->el.number)
1990
 
        currentSy->el.number= prev->number;
1991
 
    }
1992
 
  }
1993
 
 
1994
 
  if (currentSy && el==currentSy->elements) {
1995
 
    if (el->next==el) currentSy->elements= 0;
1996
 
    else currentSy->elements= el->next;
1997
 
  } else if (el==currentDr->elements) {
1998
 
    if (el->next==el) currentDr->elements= 0;
1999
 
    else currentDr->elements= el->next;
2000
 
  }
2001
 
 
2002
 
  el->ops->Kill(el);
2003
 
  currentEl= 0;
2004
 
  return 0;
2005
 
}
2006
 
 
2007
 
int GdGetLimits(void)
2008
 
{
2009
 
  if (!currentDr || !currentSy) return 1;
2010
 
  if ((currentSy->rescan || currentSy->unscanned>=0)
2011
 
      && GdScan(currentSy)) return 1;  /* memory manager failure */
2012
 
  gistD.trans.window= currentSy->trans.window;
2013
 
  gistD.flags= currentSy->flags;
2014
 
 
2015
 
  if (gistD.flags & D_LOGX) {
2016
 
    gistD.limits.xmin= exp10(gistD.trans.window.xmin);
2017
 
    gistD.limits.xmax= exp10(gistD.trans.window.xmax);
2018
 
  } else {
2019
 
    gistD.limits.xmin= gistD.trans.window.xmin;
2020
 
    gistD.limits.xmax= gistD.trans.window.xmax;
2021
 
  }
2022
 
  if (gistD.flags & D_LOGY) {
2023
 
    gistD.limits.ymin= exp10(gistD.trans.window.ymin);
2024
 
    gistD.limits.ymax= exp10(gistD.trans.window.ymax);
2025
 
  } else {
2026
 
    gistD.limits.ymin= gistD.trans.window.ymin;
2027
 
    gistD.limits.ymax= gistD.trans.window.ymax;
2028
 
  }
2029
 
  return 0;
2030
 
}
2031
 
 
2032
 
int GdSetLimits(void)
2033
 
{
2034
 
  int flags, rescan;
2035
 
  if (!currentDr || !currentSy) return 1;
2036
 
 
2037
 
  if (gistD.flags & D_LOGX) {
2038
 
    gistD.trans.window.xmin= SAFELOG(gistD.limits.xmin);
2039
 
    gistD.trans.window.xmax= SAFELOG(gistD.limits.xmax);
2040
 
  } else {
2041
 
    gistD.trans.window.xmin= gistD.limits.xmin;
2042
 
    gistD.trans.window.xmax= gistD.limits.xmax;
2043
 
  }
2044
 
  if (gistD.flags & D_LOGY) {
2045
 
    gistD.trans.window.ymin= SAFELOG(gistD.limits.ymin);
2046
 
    gistD.trans.window.ymax= SAFELOG(gistD.limits.ymax);
2047
 
  } else {
2048
 
    gistD.trans.window.ymin= gistD.limits.ymin;
2049
 
    gistD.trans.window.ymax= gistD.limits.ymax;
2050
 
  }
2051
 
 
2052
 
  flags= currentSy->flags;
2053
 
  currentSy->flags= gistD.flags;
2054
 
 
2055
 
  /* Normally, setting the limits damages the entire system.
2056
 
     However, would like to allow a special case for fixing limits to
2057
 
     their existing extreme values.  */
2058
 
  rescan= 1;
2059
 
  if ( ! ( (flags^gistD.flags) & (~(D_XMIN|D_XMAX|D_YMIN|D_YMAX)) ) ) {
2060
 
    if (((flags&D_XMIN)==(gistD.flags&D_XMIN) || (gistD.flags&D_XMIN)==0) &&
2061
 
        ((flags&D_XMAX)==(gistD.flags&D_XMAX) || (gistD.flags&D_XMAX)==0) &&
2062
 
        ((flags&D_YMIN)==(gistD.flags&D_YMIN) || (gistD.flags&D_YMIN)==0) &&
2063
 
        ((flags&D_YMAX)==(gistD.flags&D_YMAX) || (gistD.flags&D_YMAX)==0)) {
2064
 
      GpBox *w= &currentSy->trans.window;
2065
 
      if (w->xmin==gistD.trans.window.xmin &&
2066
 
          w->xmax==gistD.trans.window.xmax &&
2067
 
          w->ymin==gistD.trans.window.ymin &&
2068
 
          w->ymax==gistD.trans.window.ymax)
2069
 
        rescan= 0;
2070
 
    }
2071
 
  }
2072
 
  currentSy->trans.window= gistD.trans.window;
2073
 
  currentSy->rescan|= rescan;
2074
 
 
2075
 
  /* damage alert takes place in GdScan just before rendering */
2076
 
  return 0;
2077
 
}
2078
 
 
2079
 
int GdSaveLimits(int resetZoomed)
2080
 
{
2081
 
  if (!currentDr || !currentSy) return 1;
2082
 
  currentSy->savedWindow= currentSy->trans.window;
2083
 
  currentSy->savedFlags= currentSy->flags;
2084
 
  if (resetZoomed) currentSy->savedFlags&= ~D_ZOOMED;
2085
 
  return 0;
2086
 
}
2087
 
 
2088
 
int GdRevertLimits(int ifZoomed)
2089
 
{
2090
 
  if (!currentDr || !currentSy ||
2091
 
      (ifZoomed && !(currentSy->flags&D_ZOOMED))) return 1;
2092
 
  if (currentSy->savedFlags!=currentSy->flags ||
2093
 
      currentSy->savedWindow.xmin!=currentSy->trans.window.xmin ||
2094
 
      currentSy->savedWindow.xmax!=currentSy->trans.window.xmax ||
2095
 
      currentSy->savedWindow.ymin!=currentSy->trans.window.ymin ||
2096
 
      currentSy->savedWindow.ymax!=currentSy->trans.window.ymax) {
2097
 
    currentSy->trans.window= currentSy->savedWindow;
2098
 
    currentSy->flags= currentSy->savedFlags;
2099
 
    currentSy->rescan= 1;
2100
 
  }
2101
 
  return 0;
2102
 
}
2103
 
 
2104
 
int GdSetPort(void)
2105
 
{
2106
 
  GpBox *v, oldBox;
2107
 
  if (!currentDr || !currentSy) return 1;
2108
 
 
2109
 
  currentSy->el.hidden= gistD.hidden;
2110
 
  /*
2111
 
  if (gistD.legend) {
2112
 
    currentSy->el.legend= Copy1(gistD.legend, strlen(gistD.legend)+1);
2113
 
  }
2114
 
  */
2115
 
 
2116
 
  /* First, damage current coordinate system box.  */
2117
 
  Damage(currentSy, (GdElement *)0);
2118
 
 
2119
 
  /* Save old box, set new ticks, viewport, and correponding box */
2120
 
  oldBox= currentSy->el.box;
2121
 
  v= &currentSy->trans.viewport;
2122
 
  currentSy->ticks= gistD.ticks;
2123
 
  *v= gistD.trans.viewport;
2124
 
  GuessBox(&currentSy->el.box, &gistD.trans.viewport, &gistD.ticks);
2125
 
 
2126
 
  /* Since stacking order hasn't changed, new box must be damaged
2127
 
     if it is not contained in the old box.  */
2128
 
  v= &currentSy->el.box;
2129
 
  if (v->xmin<oldBox.xmin || v->xmax>oldBox.xmax ||
2130
 
      v->ymin<oldBox.ymin || v->ymax>oldBox.ymax)
2131
 
    Damage(currentSy, (GdElement *)0);
2132
 
 
2133
 
  return 0;
2134
 
}
2135
 
 
2136
 
GpBox *GdClearSystem(void)
2137
 
{
2138
 
  GpBox *dBox;
2139
 
  int n, nel;
2140
 
  GeSystem *sys, *sys0;
2141
 
  GdElement *el, *el0;
2142
 
  /* Intended for use with animation... */
2143
 
  if (!currentDr || !currentSy) return 0;
2144
 
 
2145
 
  Gd_KillRing(currentSy->elements);
2146
 
  currentSy->elements= 0;
2147
 
  currentSy->el.number= currentSy->unscanned= -1;
2148
 
  currentSy->rescan= 0;
2149
 
 
2150
 
  sys0= currentDr->systems;
2151
 
  el0= currentDr->elements;
2152
 
  nel= -1;
2153
 
  if ((sys= sys0)) do {
2154
 
    if (sys==currentSy) continue;
2155
 
    n= currentSy->el.number;
2156
 
    if (n>nel) nel= n;
2157
 
    sys= (GeSystem *)sys->el.next;
2158
 
  } while (sys!=sys0);
2159
 
  if ((el= el0)) do {
2160
 
    n= el->number;
2161
 
    if (n>nel) nel= n;
2162
 
    el= el->next;
2163
 
  } while (el!=el0);
2164
 
  currentDr->nElements= nel+1;
2165
 
 
2166
 
  if (currentSy->flags & (D_XMIN|D_XMAX|D_YMIN|D_YMAX)) {
2167
 
    /* Some extreme value set, damage whole box */
2168
 
    dBox= &currentSy->el.box;
2169
 
    Damage(currentSy, (GdElement *)0);
2170
 
  } else {
2171
 
    /* All limits fixed, damage only viewport */
2172
 
    dBox= &currentSy->trans.viewport;
2173
 
    Damage(currentSy, &currentSy->el);
2174
 
  }
2175
 
 
2176
 
  return dBox;
2177
 
}
2178
 
 
2179
 
/* ------------------------------------------------------------------------ */