3
Virtual functions for Drauing class.
5
$Id: draw0.c,v 1.1 2003/03/08 15:26:45 travo Exp $
7
/* Copyright (c) 1994. The Regents of the University of California.
8
All rights reserved. */
15
extern char *strcpy(char *, const char *);
17
extern double log10(double);
18
#define SAFELOG0 (-999.)
19
#define SAFELOG(x) ((x)>0? log10(x) : ((x)<0? log10(-(x)) : -999.))
21
extern void Gd_KillRing(void *elv);
23
static void KillElement(GdElement *el);
24
static void LinesKill(void *el);
25
static void DisjointKill(void *el);
26
static void TextKill(void *el);
27
static void CellsKill(void *el);
28
static void PolysKill(void *el);
29
static void MeshKill(void *el);
30
static void FilledKill(void *el);
31
static void VectorsKill(void *el);
32
static void KillConGrps(GeLines **grps, int ngrps);
33
static void ContoursKill(void *el);
34
static void SystemKill(void *el);
35
extern void Gd_KillMeshXY(void *vMeshEl);
37
static int LinesGet(void *el);
38
static int DisjointGet(void *el);
39
static int TextGet(void *el);
40
static int CellsGet(void *el);
41
static int PolysGet(void *el);
42
static int MeshGet(void *el);
43
static int FilledGet(void *el);
44
static int VectorsGet(void *el);
45
static int ContoursGet(void *el);
46
static int SystemGet(void *el);
47
extern void Gd_MeshXYGet(void *vMeshEl);
49
static int LinesSet(void *el, int xyzChanged);
50
extern void Gd_LinesSubSet(void *el);
51
static int DisjointSet(void *el, int xyzChanged);
52
static int TextSet(void *el, int xyzChanged);
53
static int CellsSet(void *el, int xyzChanged);
54
static int PolysSet(void *el, int xyzChanged);
55
static void MeshXYSet(void *vMeshEl, int xyzChanged);
56
static int MeshSet(void *el, int xyzChanged);
57
static int FilledSet(void *el, int xyzChanged);
58
static int VectorsSet(void *el, int xyzChanged);
59
static int ContoursSet(void *el, int xyzChanged);
60
static int SystemSet(void *el, int xyzChanged);
62
static int LinesDraw(void *el, int xIsLog, int yIsLog);
63
static int DisjointDraw(void *el, int xIsLog, int yIsLog);
64
static int TextDraw(void *el, int xIsLog, int yIsLog);
65
static int CellsDraw(void *el, int xIsLog, int yIsLog);
66
static int PolysDraw(void *el, int xIsLog, int yIsLog);
67
static void MeshDrawSet(GaQuadMesh *mesh, void *vMeshEl,
68
int xIsLog, int yIsLog);
69
static int MeshDraw(void *el, int xIsLog, int yIsLog);
70
static int FilledDraw(void *el, int xIsLog, int yIsLog);
71
static int VectorsDraw(void *el, int xIsLog, int yIsLog);
72
static int ContoursDraw(void *el, int xIsLog, int yIsLog);
73
static int SystemDraw(void *el, int xIsLog, int yIsLog);
75
static int LinesScan(void *el, int flags, GpBox *limits);
76
static int DisjointScan(void *el, int flags, GpBox *limits);
77
static int TextScan(void *el, int flags, GpBox *limits);
78
static int CellsScan(void *el, int flags, GpBox *limits);
79
static int PolysScan(void *el, int flags, GpBox *limits);
80
static int MeshXYScan(void *vMeshEl, int flags, GpBox *limits, GpBox *box);
81
static int MeshScan(void *el, int flags, GpBox *limits);
82
static int FilledScan(void *el, int flags, GpBox *limits);
83
static int VectorsScan(void *el, int flags, GpBox *limits);
84
static int ContoursScan(void *el, int flags, GpBox *limits);
85
static int SystemScan(void *el, int flags, GpBox *limits);
87
static void NoMargin(void *el, GpBox *margin);
88
static void LinesMargin(void *el, GpBox *margin);
89
static void DisjointMargin(void *el, GpBox *margin);
90
static void TextMargin(void *el, GpBox *margin);
91
static void MeshMargin(void *el, GpBox *margin);
92
static void VectorsMargin(void *el, GpBox *margin);
93
static void ContoursMargin(void *el, GpBox *margin);
95
extern void Gd_ScanZ(long n, const GpReal *z, GpReal *zmin, GpReal *zmax);
96
static int ScanMn(long n, GpReal *x, GpReal *y, GpReal ymin,
97
GpReal *xmin, GpReal *xmax);
98
static int ScanMx(long n, GpReal *x, GpReal *y, GpReal ymax,
99
GpReal *xmin, GpReal *xmax);
100
static int ScanMnMx(long n, GpReal *x, GpReal *y, GpReal ymin, GpReal ymax,
101
GpReal *xmin, GpReal *xmax);
102
static void ScanRXY(long n, GpReal *x, GpReal *y,
103
int flags, GpBox *limits, GpBox *box);
104
static int GetLogZ(long n, GpReal *z, GpReal **zlog,
105
GpReal *zmin, GpReal *zmax);
106
static int Get_LogZ(long n, long nndc, GpReal *z, GpReal **zlog,
107
GpReal *zmin, GpReal *zmax);
109
extern int Gd_MakeContours(GeContours *con);
110
extern int Gd_DrawRing(void *elv, int xIsLog, int yIsLog,
111
GeSystem *sys, int t);
112
extern void Gd_NextMeshBlock(long *ii, long *jj, long len, long iMax,
113
int *reg, int region);
115
/* ------------------------------------------------------------------------ */
116
/* Set virtual function tables */
118
extern GdOpTable *GetDrawingOpTables(void);
119
static GdOpTable opTables[E_SYSTEM+1]= {
120
{ E_NONE, 0, 0, 0, 0, 0, 0 },
121
{ E_LINES, &LinesKill, &LinesGet, &LinesSet,
122
&LinesDraw, &LinesScan, &LinesMargin },
123
{ E_DISJOINT, &DisjointKill, &DisjointGet, &DisjointSet,
124
&DisjointDraw, &DisjointScan, &DisjointMargin },
125
{ E_TEXT, &TextKill, &TextGet, &TextSet,
126
&TextDraw, &TextScan, &TextMargin },
127
{ E_MESH, &MeshKill, &MeshGet, &MeshSet,
128
&MeshDraw, &MeshScan, &MeshMargin },
129
{ E_FILLED, &FilledKill, &FilledGet, &FilledSet,
130
&FilledDraw, &FilledScan, &NoMargin },
131
{ E_VECTORS, &VectorsKill, &VectorsGet, &VectorsSet,
132
&VectorsDraw, &VectorsScan, &VectorsMargin },
133
{ E_CONTOURS, &ContoursKill, &ContoursGet, &ContoursSet,
134
&ContoursDraw, &ContoursScan, &ContoursMargin },
135
{ E_CELLS, &CellsKill, &CellsGet, &CellsSet,
136
&CellsDraw, &CellsScan, &NoMargin },
137
{ E_POLYS, &PolysKill, &PolysGet, &PolysSet,
138
&PolysDraw, &PolysScan, &NoMargin },
139
{ E_SYSTEM, &SystemKill, &SystemGet, &SystemSet,
140
&SystemDraw, &SystemScan, &NoMargin }
143
/* this is called at the first call to GdNewDrawing */
144
GdOpTable *GetDrawingOpTables(void)
149
/* ------------------------------------------------------------------------ */
150
/* Destructors for drawing elements are private, accessed via the
151
Kill virtual function */
153
void Gd_KillRing(void *elv)
155
GdElement *el, *next= elv;
158
if (el == next) next= 0;
163
static void KillElement(GdElement *el)
165
GdElement *next= el->next;
166
if (el->legend) p_free(el->legend);
168
if (next==el) next= 0;
169
else { next->prev= el->prev; el->prev->next= next; }
175
static void LinesKill(void *el)
178
if (lines->x) p_free(lines->x);
179
if (lines->y) p_free(lines->y);
180
if (lines->xlog) p_free(lines->xlog);
181
if (lines->ylog) p_free(lines->ylog);
185
static void DisjointKill(void *el)
187
GeDisjoint *lines= el;
188
if (lines->x) p_free(lines->x);
189
if (lines->y) p_free(lines->y);
190
if (lines->xlog) p_free(lines->xlog);
191
if (lines->ylog) p_free(lines->ylog);
192
if (lines->xq) p_free(lines->xq);
193
if (lines->yq) p_free(lines->yq);
194
if (lines->xqlog) p_free(lines->xqlog);
195
if (lines->yqlog) p_free(lines->yqlog);
199
static void TextKill(void *el)
202
if (text->text) p_free(text->text);
206
static void CellsKill(void *el)
209
if (cells->colors) p_free(cells->colors);
213
static void PolysKill(void *el)
216
if (polys->x) p_free(polys->x);
217
if (polys->y) p_free(polys->y);
218
if (polys->xlog) p_free(polys->xlog);
219
if (polys->ylog) p_free(polys->ylog);
220
if (polys->pn) p_free(polys->pn);
221
if (polys->colors) p_free(polys->colors);
225
static void MeshKill(void *el)
231
static void FilledKill(void *el)
236
if (!(fill->noCopy&NOCOPY_COLORS)) p_free(fill->colors);
237
else if (GdFree) GdFree(fill->colors);
242
static void VectorsKill(void *el)
246
if (!(vec->noCopy&NOCOPY_UV)) {
247
if (vec->u) p_free(vec->u);
248
if (vec->v) p_free(vec->v);
250
if (vec->u) GdFree(vec->u);
251
if (vec->v) GdFree(vec->v);
256
static void KillConGrps(GeLines **grps, int ngrps)
259
for (i=0 ; i<ngrps ; i++) { Gd_KillRing(grps[i]); grps[i]= 0; }
262
static void ContoursKill(void *el)
267
if (!(con->noCopy&NOCOPY_Z)) p_free(con->z);
268
else if (GdFree) GdFree(con->z);
270
if (con->levels) p_free(con->levels);
272
KillConGrps(con->groups, con->nLevels);
278
static void SystemKill(void *el)
281
Gd_KillRing(sys->elements);
285
void Gd_KillMeshXY(void *vMeshEl)
287
GeMesh *meshEl= vMeshEl;
288
GaQuadMesh *mesh= &meshEl->mesh;
289
int noCopy= meshEl->noCopy;
290
if (!(noCopy&NOCOPY_MESH)) {
291
if (mesh->x) p_free(mesh->x);
292
if (mesh->y) p_free(mesh->y);
294
if (mesh->x) GdFree(mesh->x);
295
if (mesh->y) GdFree(mesh->y);
298
if (!(noCopy&NOCOPY_REG)) p_free(mesh->reg);
299
else if (GdFree) GdFree(mesh->reg);
301
if (mesh->triangle) {
302
if (!(noCopy&NOCOPY_TRI)) p_free(mesh->triangle);
303
else if (GdFree) GdFree(mesh->triangle);
307
/* ------------------------------------------------------------------------ */
308
/* GetProps virtual function loads gistA, gistD from GdElement */
310
static int LinesGet(void *el)
313
gistD.hidden= e->el.hidden;
314
gistD.legend= e->el.legend;
324
static int DisjointGet(void *el)
327
gistD.hidden= e->el.hidden;
328
gistD.legend= e->el.legend;
338
static int TextGet(void *el)
341
gistD.hidden= e->el.hidden;
342
gistD.legend= e->el.legend;
350
static int CellsGet(void *el)
353
gistD.hidden= e->el.hidden;
354
gistD.legend= e->el.legend;
359
gistD.width= e->width;
360
gistD.height= e->height;
361
gistD.colors= e->colors;
366
static int PolysGet(void *el)
369
gistD.hidden= e->el.hidden;
370
gistD.legend= e->el.legend;
375
gistD.colors= e->colors;
381
static int MeshGet(void *el)
385
gistD.hidden= e->el.hidden;
386
gistD.legend= e->el.legend;
387
gistD.boundary= e->boundary;
388
gistD.inhibit= e->inhibit;
393
static int FilledGet(void *el)
397
gistD.hidden= e->el.hidden;
398
gistD.legend= e->el.legend;
399
gistD.nColumns= e->nColumns;
400
gistD.colors= e->colors;
406
static int VectorsGet(void *el)
410
gistD.hidden= e->el.hidden;
411
gistD.legend= e->el.legend;
414
gistD.scale= e->scale;
421
static int ContoursGet(void *el)
425
gistD.hidden= e->el.hidden;
426
gistD.legend= e->el.legend;
428
gistD.nLevels= e->nLevels;
429
gistD.levels= e->levels;
436
static int SystemGet(void *el)
439
gistD.hidden= e->el.hidden;
440
gistD.legend= e->el.legend;
444
void Gd_MeshXYGet(void *vMeshEl)
446
GeMesh *meshEl= vMeshEl;
447
GaQuadMesh *mesh= &meshEl->mesh;
448
gistD.noCopy= meshEl->noCopy;
449
gistD.mesh.iMax= mesh->iMax;
450
gistD.mesh.jMax= mesh->jMax;
451
gistD.mesh.x= mesh->x;
452
gistD.mesh.y= mesh->y;
453
gistD.mesh.reg= mesh->reg;
454
gistD.mesh.triangle= mesh->triangle;
455
gistD.region= meshEl->region;
458
/* ------------------------------------------------------------------------ */
459
/* SetProps virtual function loads GdElement from gistA, gistD */
461
static int LinesSet(void *el, int xyzChanged)
465
e->el.legend= gistD.legend;
466
if (xyzChanged & CHANGE_XY) {
470
if (e->xlog) { p_free(e->xlog); e->xlog= 0; }
471
if (e->ylog) { p_free(e->ylog); e->ylog= 0; }
476
void Gd_LinesSubSet(void *el)
479
e->el.hidden= gistD.hidden;
485
static int DisjointSet(void *el, int xyzChanged)
488
e->el.hidden= gistD.hidden;
489
e->el.legend= gistD.legend;
496
if (xyzChanged & CHANGE_XY) {
497
if (e->xlog) { p_free(e->xlog); e->xlog= 0; }
498
if (e->ylog) { p_free(e->ylog); e->ylog= 0; }
499
if (e->xqlog) { p_free(e->xqlog); e->xqlog= 0; }
500
if (e->yqlog) { p_free(e->yqlog); e->yqlog= 0; }
506
static int TextSet(void *el, int xyzChanged)
509
e->el.hidden= gistD.hidden;
510
e->el.legend= gistD.legend;
519
static int CellsSet(void *el, int xyzChanged)
522
e->el.hidden= gistD.hidden;
523
e->el.legend= gistD.legend;
528
e->width= gistD.width;
529
e->height= gistD.height;
530
e->colors= gistD.colors;
534
static int PolysSet(void *el, int xyzChanged)
538
e->el.legend= gistD.legend;
539
if (xyzChanged & CHANGE_XY) {
543
if (e->xlog) { p_free(e->xlog); e->xlog= 0; }
544
if (e->ylog) { p_free(e->ylog); e->ylog= 0; }
547
e->colors= gistD.colors;
551
static void MeshXYSet(void *vMeshEl, int xyzChanged)
553
GeMesh *meshEl= vMeshEl;
554
GaQuadMesh *mesh= &meshEl->mesh;
555
meshEl->el.legend= gistD.legend;
556
meshEl->el.hidden= gistD.hidden;
557
meshEl->noCopy= gistD.noCopy;
558
mesh->iMax= gistD.mesh.iMax;
559
mesh->jMax= gistD.mesh.jMax;
560
mesh->x= gistD.mesh.x;
561
mesh->y= gistD.mesh.y;
562
mesh->reg= gistD.mesh.reg;
563
mesh->triangle= gistD.mesh.triangle;
564
if (xyzChanged & CHANGE_XY) {
565
if (meshEl->xlog) { p_free(meshEl->xlog); meshEl->xlog= 0; }
566
if (meshEl->ylog) { p_free(meshEl->ylog); meshEl->ylog= 0; }
568
meshEl->region= gistD.region;
571
static int MeshSet(void *el, int xyzChanged)
574
MeshXYSet(el, xyzChanged);
575
e->boundary= gistD.boundary;
576
e->inhibit= gistD.inhibit;
581
static int FilledSet(void *el, int xyzChanged)
584
MeshXYSet(el, xyzChanged);
585
e->nColumns= gistD.nColumns;
586
e->colors= gistD.colors;
591
static int VectorsSet(void *el, int xyzChanged)
594
MeshXYSet(el, xyzChanged);
597
e->scale= gistD.scale;
604
static int ContoursSet(void *el, int xyzChanged)
607
int oldN= e->nLevels;
608
MeshXYSet(el, xyzChanged);
610
e->nLevels= gistD.nLevels;
611
e->levels= gistD.levels;
615
if (xyzChanged & CHANGE_Z) {
617
KillConGrps(e->groups, oldN);
618
if (oldN!=gistD.nLevels) {
623
if (gistD.nLevels>0) {
625
e->groups= (GeLines **)p_malloc(sizeof(GeLines *)*gistD.nLevels);
626
if (!e->groups || Gd_MakeContours(e)) return 1;
633
static int SystemSet(void *el, int xyzChanged)
636
e->el.hidden= gistD.hidden;
637
e->el.legend= gistD.legend;
641
/* ------------------------------------------------------------------------ */
642
/* Draw virtual function calls Gp and Ga level rendering routines */
644
static int LinesDraw(void *el, int xIsLog, int yIsLog)
647
GpReal *px= xIsLog? e->xlog : e->x;
648
GpReal *py= yIsLog? e->ylog : e->y;
650
if (e->el.hidden || n<=0) return 0;
654
return GaLines(n, px, py);
657
static int DisjointDraw(void *el, int xIsLog, int yIsLog)
660
GpReal *px= xIsLog? e->xlog : e->x;
661
GpReal *py= yIsLog? e->ylog : e->y;
662
GpReal *qx= xIsLog? e->xqlog : e->xq;
663
GpReal *qy= yIsLog? e->yqlog : e->yq;
665
if (e->el.hidden || n<=0) return 0;
667
return GpDisjoint(n, px, py, qx, qy);
670
static int TextDraw(void *el, int xIsLog, int yIsLog)
674
if (e->el.hidden || !e->text) return 0;
675
x0= xIsLog? SAFELOG(e->x0) : e->x0;
676
y0= yIsLog? SAFELOG(e->y0) : e->y0;
678
return GpText(x0, y0, e->text);
681
static int CellsDraw(void *el, int xIsLog, int yIsLog)
684
GpReal px, py, qx, qy;
686
if (e->el.hidden) return 0;
687
px= xIsLog? SAFELOG(e->px) : e->px;
688
py= yIsLog? SAFELOG(e->py) : e->py;
689
qx= xIsLog? SAFELOG(e->qx) : e->qx;
690
qy= yIsLog? SAFELOG(e->qy) : e->qy;
692
value = GpCells(px, py, qx, qy, e->width, e->height, e->width, e->colors);
693
gistA.rgb = 0; /* modest attempt at backward compatibility */
697
static int PolysDraw(void *el, int xIsLog, int yIsLog)
701
GpReal *px= xIsLog? e->xlog : e->x;
702
GpReal *py= yIsLog? e->ylog : e->y;
703
GpColor *colors= e->colors;
704
int rgb = colors? e->rgb : 0;
708
if (e->el.hidden || n<=0) return 0;
710
if (!colors) gistA.f.color = BG_COLOR;
711
if (n<2 || pn[1]>1) {
713
for (i=0 ; i<n ; i++) {
715
gistA.f.color=P_RGB(colors[j],colors[j+1],colors[j+2]), j+=3;
717
gistA.f.color = colors[i];
718
result|= GpFill(pn[i], px, py);
725
for (i=1 ; i<n ; i++) {
727
gistA.f.color=P_RGB(colors[j],colors[j+1],colors[j+2]), j+=3;
729
gistA.f.color = colors[i];
730
result|= GaFillMarker(pn[0], px, py, px[i0+i], py[i0+i]);
736
static void MeshDrawSet(GaQuadMesh *mesh, void *vMeshEl,
737
int xIsLog, int yIsLog)
739
GeMesh *meshEl= vMeshEl;
740
GaQuadMesh *msh= &meshEl->mesh;
741
GpReal *x= xIsLog? meshEl->xlog : msh->x;
742
GpReal *y= yIsLog? meshEl->ylog : msh->y;
743
mesh->iMax= msh->iMax;
744
mesh->jMax= msh->jMax;
748
mesh->triangle= msh->triangle;
751
static int MeshDraw(void *el, int xIsLog, int yIsLog)
755
if (e->el.hidden) return 0;
756
MeshDrawSet(&mesh, el, xIsLog, yIsLog);
758
return GaMesh(&mesh, e->region, e->boundary, e->inhibit);
761
static int FilledDraw(void *el, int xIsLog, int yIsLog)
765
if (e->el.hidden) return 0;
766
MeshDrawSet(&mesh, el, xIsLog, yIsLog);
769
return GaFillMesh(&mesh, e->region, e->colors, e->nColumns);
772
static int VectorsDraw(void *el, int xIsLog, int yIsLog)
776
if (e->el.hidden) return 0;
777
MeshDrawSet(&mesh, el, xIsLog, yIsLog);
781
return GaVectors(&mesh, e->region, e->u, e->v, e->scale);
784
static int ContoursDraw(void *el, int xIsLog, int yIsLog)
787
int nLevels= e->nLevels;
788
GeLines **groups= e->groups;
790
if (e->el.hidden || nLevels<=0) return 0;
791
if (!groups) return 1;
792
while (nLevels--) value|= Gd_DrawRing(*groups++, xIsLog, yIsLog, 0, 1);
796
static int SystemDraw(void *el, int xIsLog, int yIsLog)
797
/* NOTE: xIsLog input is used in a very non-standard way as the
798
index of this system. This is possible since xIsLog and yIsLog
799
are otherwise meaningless in SystemDraw. */
802
int vflags, hflags= e->flags;
803
int systemCounter= xIsLog; /* Yes, this is non-standard usage */
805
if (e->el.hidden || !e->elements) return 0;
807
xIsLog= hflags & D_LOGX;
808
yIsLog= hflags & D_LOGY;
809
GpSetTrans(&e->trans);
811
/* In order to prevent needless GaTick calls, a special feature
812
is built into GdBeginSy. */
813
hflags= e->ticks.horiz.flags;
814
vflags= e->ticks.vert.flags;
815
if (vflags & TICK_C || hflags & TICK_C) tickIn= 0;
817
GpReal tlen= e->ticks.vert.tickLen[0];
818
GpReal twid= 0.5*e->ticks.vert.tickStyle.width*DEFAULT_LINE_WIDTH;
819
tlen= (vflags&TICK_IN)? ((vflags&TICK_OUT)? 0.5 : 1.0)*tlen : 0.0;
822
port= e->trans.viewport;
823
if (vflags & TICK_L) port.xmin-= e->ticks.vert.tickOff + tlen + twid;
824
if (vflags & TICK_U) port.xmax+= e->ticks.vert.tickOff - tlen - twid;
826
tlen= e->ticks.horiz.tickLen[0];
827
twid= 0.5*e->ticks.horiz.tickStyle.width*DEFAULT_LINE_WIDTH;
828
tlen= (hflags&TICK_IN)? ((hflags&TICK_OUT)? 0.5 : 1.0)*tlen : 0.0;
829
if (hflags & TICK_L) port.ymin-= e->ticks.horiz.tickOff + tlen + twid;
830
if (hflags & TICK_U) port.ymax+= e->ticks.horiz.tickOff - tlen - twid;
833
hflags= GdBeginSy(&e->el.box, tickIn, &e->trans.viewport,
834
e->el.number, systemCounter);
836
/* Draw the elements for this coordinate system before the ticks. */
837
gistClip= 1; /* turn on clipping for elements */
838
if (hflags & 1) Gd_DrawRing(e->elements, xIsLog, yIsLog, e, 0);
840
/* Draw tick marks on top of elements. If the user has chosen a style
841
where the ticks overlap the viewport, he probably wants the ticks
842
to obstruct his data anyway. */
843
gistClip= 0; /* turn off clipping for ticks */
844
if (hflags & 2) GaAltTick(&e->ticks, xIsLog, yIsLog,
845
e->xtick, e->xlabel, e->ytick, e->ylabel);
849
/* ------------------------------------------------------------------------ */
850
/* Scan virtual function gets logs if reqd, sets box, scans xy */
852
static int ScanMn(long n, GpReal *x, GpReal *y, GpReal ymin,
853
GpReal *xmin, GpReal *xmax)
857
for (i=0 ; i<n ; i++) if (y[i]>=ymin) break;
860
for ( ; i<n ; i++) if (y[i]>=ymin) {
861
if (x[i]<xn) xn= x[i];
862
else if (x[i]>xx) xx= x[i];
869
static int ScanMx(long n, GpReal *x, GpReal *y, GpReal ymax,
870
GpReal *xmin, GpReal *xmax)
874
for (i=0 ; i<n ; i++) if (y[i]<=ymax) break;
877
for ( ; i<n ; i++) if (y[i]<=ymax) {
878
if (x[i]<xn) xn= x[i];
879
else if (x[i]>xx) xx= x[i];
886
static int ScanMnMx(long n, GpReal *x, GpReal *y, GpReal ymin, GpReal ymax,
887
GpReal *xmin, GpReal *xmax)
891
for (i=0 ; i<n ; i++) if (y[i]>=ymin && y[i]<=ymax) break;
894
for ( ; i<n ; i++) if (y[i]>=ymin && y[i]<=ymax) {
895
if (x[i]<xn) xn= x[i];
896
else if (x[i]>xx) xx= x[i];
903
static void ScanRXY(long n, GpReal *x, GpReal *y,
904
int flags, GpBox *limits, GpBox *box)
906
int dxmin= flags & D_XMIN, dxmax= flags & D_XMAX;
907
int dymin= flags & D_YMIN, dymax= flags & D_YMAX;
910
if (dxmin || dxmax) {
913
if (dymax) { xmin= box->xmin; xmax= box->xmax; any= 1; }
914
else if (box->ymin>limits->ymax) any= 0;
915
else any= ScanMx(n, x, y, limits->ymax, &xmin, &xmax);
916
} else if (box->ymax<limits->ymin) {
919
if (dymax) any= ScanMn(n, x, y, limits->ymin, &xmin, &xmax);
920
else if (box->ymin>limits->ymax) any= 0;
921
else any= ScanMnMx(n, x, y, limits->ymin, limits->ymax, &xmin, &xmax);
924
if (dxmin) limits->xmin= xmin;
925
if (dxmax) limits->xmax= xmax;
926
} else { /* GdScan requires min>max if no curves visible */
928
if (dxmax) limits->xmax= 0.0;
929
if (limits->xmax>0.0) limits->xmin= 1.1*limits->xmax;
930
else limits->xmin= 0.9*limits->xmax+1.0;
931
} else { /* dxmax is set */
932
if (limits->xmin>0.0) limits->xmax= 0.9*limits->xmin;
933
else limits->xmax= 1.1*limits->xmin-1.0;
937
if (dymin || dymax) {
940
if (dxmax) { ymin= box->ymin; ymax= box->ymax; any= 1; }
941
else if (box->xmin>limits->xmax) any= 0;
942
else any= ScanMx(n, y, x, limits->xmax, &ymin, &ymax);
943
} else if (box->xmax<limits->xmin) {
946
if (dxmax) any= ScanMn(n, y, x, limits->xmin, &ymin, &ymax);
947
else if (box->xmin>limits->xmax) any= 0;
948
else any= ScanMnMx(n, y, x, limits->xmin, limits->xmax, &ymin, &ymax);
951
if (dymin) limits->ymin= ymin;
952
if (dymax) limits->ymax= ymax;
953
} else { /* GdScan requires min>max if no curves visible */
955
if (dymax) limits->ymax= 0.0;
956
if (limits->ymax>0.0) limits->ymin= 1.1*limits->ymax;
957
else limits->ymin= 0.9*limits->ymax+1.0;
958
} else { /* dymax is set */
959
if (limits->ymin>0.0) limits->ymax= 0.9*limits->ymin;
960
else limits->ymax= 1.1*limits->ymin-1.0;
966
static int GetLogZ(long n, GpReal *z, GpReal **zlog,
967
GpReal *zmin, GpReal *zmax)
969
GpReal *zl= (GpReal *)p_malloc(sizeof(GpReal)*n);
973
for (i=0 ; i<n ; i++) zl[i]= SAFELOG(z[i]);
974
if (zmin) Gd_ScanZ(n, zl, zmin, zmax);
976
strcpy(gistError, "memory manager failed in Gd log function");
982
static int Get_LogZ(long n, long nndc, GpReal *z, GpReal **zlog,
983
GpReal *zmin, GpReal *zmax)
985
GpReal *zl= (GpReal *)p_malloc(sizeof(GpReal)*n);
989
for (i=0 ; i<nndc ; i++) zl[i]= z[i];
990
for ( ; i<n ; i++) zl[i]= SAFELOG(z[i]);
991
if (zmin) Gd_ScanZ(n-nndc, zl+nndc, zmin, zmax);
993
strcpy(gistError, "memory manager failed in Gd_log function");
999
static int LinesScan(void *el, int flags, GpBox *limits)
1004
/* First, get log values if necessary, and set box */
1005
if (flags & D_LOGX) {
1006
if (!e->xlog && GetLogZ(e->n, e->x, &e->xlog,
1007
&e->logBox.xmin, &e->logBox.xmax)) return 1;
1008
e->el.box.xmin= e->logBox.xmin;
1009
e->el.box.xmax= e->logBox.xmax;
1012
e->el.box.xmin= e->linBox.xmin;
1013
e->el.box.xmax= e->linBox.xmax;
1016
if (flags & D_LOGY) {
1017
if (!e->ylog && GetLogZ(e->n, e->y, &e->ylog,
1018
&e->logBox.ymin, &e->logBox.ymax)) return 1;
1019
e->el.box.ymin= e->logBox.ymin;
1020
e->el.box.ymax= e->logBox.ymax;
1023
e->el.box.ymin= e->linBox.ymin;
1024
e->el.box.ymax= e->linBox.ymax;
1028
if (flags & D_RESTRICT) {
1029
/* Scan points, restricting x limits to lie within fixed y limits
1030
and vice-versa. Assume that limits.min<limits.max. */
1031
ScanRXY(e->n, x, y, flags, limits, &e->el.box);
1033
/* Unrestricted limits are either fixed or same as bounding box. */
1034
if (flags & D_XMIN) limits->xmin= e->el.box.xmin;
1035
if (flags & D_XMAX) limits->xmax= e->el.box.xmax;
1036
if (flags & D_YMIN) limits->ymin= e->el.box.ymin;
1037
if (flags & D_YMAX) limits->ymax= e->el.box.ymax;
1043
static int DisjointScan(void *el, int flags, GpBox *limits)
1046
GpReal *x, *y, *xq, *yq;
1047
GpReal xymin, xymax;
1049
/* First, get log values if necessary, and set box */
1050
if (flags & D_LOGX) {
1051
if (!e->xlog && GetLogZ(e->n, e->x, &e->xlog,
1052
&e->logBox.xmin, &e->logBox.xmax)) return 1;
1053
e->el.box.xmin= e->logBox.xmin;
1054
e->el.box.xmax= e->logBox.xmax;
1056
if (!e->xqlog && GetLogZ(e->n, e->xq, &e->xqlog,
1057
&xymin, &xymax)) return 1;
1058
if (xymin<e->el.box.xmin) e->el.box.xmin= e->logBox.xmin;
1059
if (xymax>e->el.box.xmax) e->el.box.xmax= e->logBox.xmax;
1062
e->el.box.xmin= e->linBox.xmin;
1063
e->el.box.xmax= e->linBox.xmax;
1067
if (flags & D_LOGY) {
1068
if (!e->ylog && GetLogZ(e->n, e->y, &e->ylog,
1069
&e->logBox.ymin, &e->logBox.ymax)) return 1;
1070
e->el.box.ymin= e->logBox.ymin;
1071
e->el.box.ymax= e->logBox.ymax;
1073
if (!e->yqlog && GetLogZ(e->n, e->yq, &e->yqlog,
1074
&xymin, &xymax)) return 1;
1075
if (xymin<e->el.box.ymin) e->el.box.ymin= e->logBox.ymin;
1076
if (xymax>e->el.box.ymax) e->el.box.ymax= e->logBox.ymax;
1079
e->el.box.ymin= e->linBox.ymin;
1080
e->el.box.ymax= e->linBox.ymax;
1085
if (flags & D_RESTRICT) {
1086
/* Scan points, restricting x limits to lie within fixed y limits
1087
and vice-versa. Assume that limits.min<limits.max. */
1089
ScanRXY(e->n, x, y, flags, limits, &e->el.box);
1090
ScanRXY(e->n, xq, yq, flags, &box, &e->el.box);
1091
GpSwallow(limits, &box);
1093
/* Unrestricted limits are either fixed or same as bounding box. */
1094
if (flags & D_XMIN) limits->xmin= e->el.box.xmin;
1095
if (flags & D_XMAX) limits->xmax= e->el.box.xmax;
1096
if (flags & D_YMIN) limits->ymin= e->el.box.ymin;
1097
if (flags & D_YMAX) limits->ymax= e->el.box.ymax;
1103
static int TextScan(void *el, int flags, GpBox *limits)
1109
if (flags & D_LOGX) x0= SAFELOG(x0);
1110
if (flags & D_LOGY) y0= SAFELOG(y0);
1112
if (flags & D_XMIN) limits->xmin= x0;
1113
if (flags & D_XMAX) limits->xmax= x0;
1114
if (flags & D_YMIN) limits->ymin= y0;
1115
if (flags & D_YMAX) limits->ymax= y0;
1119
static int CellsScan(void *el, int flags, GpBox *limits)
1124
if (e->px<e->qx) { x[0]= e->px; x[1]= e->qx; }
1125
else { x[0]= e->qx; x[1]= e->px; }
1126
if (e->py<e->qy) { y[0]= e->py; y[1]= e->qy; }
1127
else { y[0]= e->qy; y[1]= e->py; }
1129
/* First, get log values if necessary, and set box */
1130
if (flags & D_LOGX) {
1131
e->el.box.xmin= SAFELOG(x[0]);
1132
e->el.box.xmax= SAFELOG(x[1]);
1134
e->el.box.xmin= x[0];
1135
e->el.box.xmax= x[1];
1137
if (flags & D_LOGY) {
1138
e->el.box.ymin= SAFELOG(y[0]);
1139
e->el.box.ymax= SAFELOG(y[1]);
1141
e->el.box.ymin= y[0];
1142
e->el.box.ymax= y[1];
1145
if (flags & D_XMIN) limits->xmin= e->el.box.xmin;
1146
if (flags & D_XMAX) limits->xmax= e->el.box.xmax;
1147
if (flags & D_YMIN) limits->ymin= e->el.box.ymin;
1148
if (flags & D_YMAX) limits->ymax= e->el.box.ymax;
1153
static int PolysScan(void *el, int flags, GpBox *limits)
1158
long nndc= (e->n<2 || e->pn[1]>1)? 0 : e->pn[0];
1160
/* compute total number of points */
1161
for (i=0 ; i<e->n ; i++) ntot+= e->pn[i];
1163
/* First, get log values if necessary, and set box */
1164
if (flags & D_LOGX) {
1165
if (!e->xlog && Get_LogZ(ntot, nndc, e->x, &e->xlog,
1166
&e->logBox.xmin, &e->logBox.xmax)) return 1;
1167
e->el.box.xmin= e->logBox.xmin;
1168
e->el.box.xmax= e->logBox.xmax;
1171
e->el.box.xmin= e->linBox.xmin;
1172
e->el.box.xmax= e->linBox.xmax;
1175
if (flags & D_LOGY) {
1176
if (!e->ylog && Get_LogZ(ntot, nndc, e->y, &e->ylog,
1177
&e->logBox.ymin, &e->logBox.ymax)) return 1;
1178
e->el.box.ymin= e->logBox.ymin;
1179
e->el.box.ymax= e->logBox.ymax;
1182
e->el.box.ymin= e->linBox.ymin;
1183
e->el.box.ymax= e->linBox.ymax;
1187
if (flags & D_RESTRICT) {
1188
/* Scan points, restricting x limits to lie within fixed y limits
1189
and vice-versa. Assume that limits.min<limits.max. */
1190
ScanRXY(ntot-nndc, x+nndc, y+nndc, flags, limits, &e->el.box);
1192
/* Unrestricted limits are either fixed or same as bounding box. */
1193
if (flags & D_XMIN) limits->xmin= e->el.box.xmin;
1194
if (flags & D_XMAX) limits->xmax= e->el.box.xmax;
1195
if (flags & D_YMIN) limits->ymin= e->el.box.ymin;
1196
if (flags & D_YMAX) limits->ymax= e->el.box.ymax;
1202
static int MeshXYScan(void *vMeshEl, int flags, GpBox *limits, GpBox *box)
1204
GeMesh *meshEl= vMeshEl;
1205
GaQuadMesh *mesh= &meshEl->mesh;
1208
/* First, get log values if necessary, and set box */
1209
if (flags & D_LOGX) {
1210
long len= mesh->iMax*mesh->jMax;
1211
int region= meshEl->region;
1213
long i, j, iMax= mesh->iMax;
1214
int *reg= mesh->reg, first= 1;
1216
if (!meshEl->xlog && GetLogZ(len, mesh->x, &meshEl->xlog, 0, 0))
1218
for (i=0 ; i<len ; ) {
1219
Gd_NextMeshBlock(&i, &j, len, iMax, reg, region);
1221
Gd_ScanZ(j-i, meshEl->xlog+i, &xmin, &xmax);
1223
meshEl->logBox.xmin= xmin;
1224
meshEl->logBox.xmax= xmax;
1227
if (xmin<meshEl->logBox.xmin) meshEl->logBox.xmin= xmin;
1228
if (xmax>meshEl->logBox.xmax) meshEl->logBox.xmax= xmax;
1232
box->xmin= meshEl->logBox.xmin;
1233
box->xmax= meshEl->logBox.xmax;
1236
box->xmin= meshEl->linBox.xmin;
1237
box->xmax= meshEl->linBox.xmax;
1240
if (flags & D_LOGY) {
1241
long len= mesh->iMax*mesh->jMax;
1242
int region= meshEl->region;
1244
long i, j, iMax= mesh->iMax;
1245
int *reg= mesh->reg, first= 1;
1247
if (!meshEl->ylog && GetLogZ(len, mesh->y, &meshEl->ylog, 0, 0))
1249
for (i=0 ; i<len ; ) {
1250
Gd_NextMeshBlock(&i, &j, len, iMax, reg, region);
1252
Gd_ScanZ(j-i, meshEl->ylog+i, &ymin, &ymax);
1254
meshEl->logBox.ymin= ymin;
1255
meshEl->logBox.ymax= ymax;
1258
if (ymin<meshEl->logBox.ymin) meshEl->logBox.ymin= ymin;
1259
if (ymax>meshEl->logBox.ymax) meshEl->logBox.ymax= ymax;
1263
box->ymin= meshEl->logBox.ymin;
1264
box->ymax= meshEl->logBox.ymax;
1267
box->ymin= meshEl->linBox.ymin;
1268
box->ymax= meshEl->linBox.ymax;
1272
if (flags & D_RESTRICT) {
1273
/* Scan points, restricting x limits to lie within fixed y limits
1274
and vice-versa. Assume that limits.min<limits.max. */
1275
long len= mesh->iMax*mesh->jMax;
1276
int region= meshEl->region;
1278
long i, j, iMax= mesh->iMax;
1279
int *reg= mesh->reg, first= 1;
1281
for (i=0 ; i<len ; ) {
1282
Gd_NextMeshBlock(&i, &j, len, iMax, reg, region);
1284
ScanRXY(j-i, x+i, y+i, flags, limits, &tbox);
1285
if (first) { *box= tbox; first= 0; }
1286
else GpSwallow(box, &tbox);
1290
/* Unrestricted limits are either fixed or same as bounding box. */
1291
if (flags & D_XMIN) limits->xmin= box->xmin;
1292
if (flags & D_XMAX) limits->xmax= box->xmax;
1293
if (flags & D_YMIN) limits->ymin= box->ymin;
1294
if (flags & D_YMAX) limits->ymax= box->ymax;
1300
static int MeshScan(void *el, int flags, GpBox *limits)
1303
return MeshXYScan(el, flags, limits, &e->el.box);
1306
static int FilledScan(void *el, int flags, GpBox *limits)
1309
return MeshXYScan(el, flags, limits, &e->el.box);
1312
static int VectorsScan(void *el, int flags, GpBox *limits)
1315
return MeshXYScan(el, flags, limits, &e->el.box);
1318
static int ContoursScan(void *el, int flags, GpBox *limits)
1321
GpBox lims= *limits;
1322
GeLines *elx, *el0, **groups= e->groups;
1323
int i, value= 0, none= 1;
1324
for (i=0 ; i<e->nLevels ; i++) {
1326
if ((elx= el0)) do {
1327
value|= LinesScan(elx, flags, &lims);
1328
if (none) { *limits= lims; e->el.box= lims; }
1329
else { GpSwallow(limits, &lims); GpSwallow(&e->el.box, &lims); }
1331
elx= (GeLines *)elx->el.next;
1332
} while (elx != el0);
1334
if (none) value= MeshXYScan(el, flags, limits, &e->el.box);
1339
static int SystemScan(void *el, int flags, GpBox *limits)
1341
return 0; /* cannot ever happen... */
1344
/* ------------------------------------------------------------------------ */
1345
/* Margin virtual function returns margin box */
1348
static void NoMargin(void *el, GpBox *margin)
1350
margin->xmin= margin->xmax= margin->ymin= margin->ymax= 0.0;
1353
static void LinesMargin(void *el, GpBox *margin)
1355
/* This only accounts for line width, ignoring other decorations--
1356
other decorations seem unlikely outside coordinate systems */
1358
margin->xmin= margin->xmax= margin->ymin= margin->ymax=
1359
0.5*lines->l.width*DEFAULT_LINE_WIDTH;
1362
static void DisjointMargin(void *el, GpBox *margin)
1364
GeDisjoint *lines= el;
1365
margin->xmin= margin->xmax= margin->ymin= margin->ymax=
1366
0.5*lines->l.width*DEFAULT_LINE_WIDTH;
1369
static void TextMargin(void *el, GpBox *margin)
1371
/* The actual text box cannot be computed without text metric data--
1372
the following is a crude guess based on character counts and an
1373
assumed width/height ratio of 0.6 (as in 9x15) and descent/height
1374
ratio of 0.2. This should be close for Courier, but it probably
1375
way off in width for the proportional fonts. */
1377
GpReal width, x0, y0, dx, dy;
1379
int nLines= GtTextShape(text->text, &text->t, (WidthFunction)0, &width);
1381
dx= text->t.height*width*0.6;
1382
dy= text->t.height*((GpReal)nLines);
1384
GtGetAlignment(&text->t, &alignH, &alignV);
1385
if (alignH==TH_LEFT) {
1387
} else if (alignH==TH_CENTER) {
1392
if (alignV==TV_TOP || alignV==TV_CAP) {
1394
} else if (alignH==TV_HALF) {
1395
y0= -0.1*text->t.height - 0.5*dy;
1396
} else if (alignH==TV_BASE) {
1397
y0= -0.2*text->t.height;
1402
if (gistA.t.orient==TX_RIGHT) {
1404
margin->xmax= x0 + dx;
1406
margin->ymax= y0 + dy;
1407
} else if (gistA.t.orient==TX_LEFT) {
1408
margin->xmin= x0 - dx;
1410
margin->ymin= y0 - dy;
1412
} else if (gistA.t.orient==TX_UP) {
1414
margin->xmax= y0 + dy;
1416
margin->ymax= x0 + dx;
1418
margin->xmin= y0 - dy;
1420
margin->ymin= x0 - dx;
1425
static void MeshMargin(void *el, GpBox *margin)
1428
margin->xmin= margin->xmax= margin->ymin= margin->ymax=
1429
0.5*mesh->l.width*DEFAULT_LINE_WIDTH;
1433
static void VectorsMargin(void *el, GpBox *margin)
1435
/* This is a wild guess-- otherwise must scan (u, v) --
1436
should never arise in practice */
1437
/* GeVectors *vec= el; */
1438
margin->xmin= margin->xmax= margin->ymin= margin->ymax= 0.05;
1441
static void ContoursMargin(void *el, GpBox *margin)
1443
/* Should never actually happen */
1444
GeContours *con= el;
1445
margin->xmin= margin->xmax= margin->ymin= margin->ymax=
1446
0.5*con->l.width*DEFAULT_LINE_WIDTH;
1449
/* ------------------------------------------------------------------------ */