source: Sophya/trunk/SophyaPI/PI/piaxes.cc@ 2138

Last change on this file since 2138 was 2138, checked in by ansari, 23 years ago

1/ Classes PILineAtt et PIGrCoord mises dans des fichiers separes

(pigraphgen.h .cc ---> pilineatt.h .cc pigrcoord.h .cc)

2/ Classe PIDraw3DWdg mis ds fichiers separes (pi3dwdg.h .cc)
3/ Mise a jour documentation
4/ Mise a jour programmes test et MAJ Makefile

Reza , 29/7/2002

File size: 22.3 KB
RevLine 
[2080]1// Module PI : Peida Interactive PIAxes
2// Methodes de trace des axes
3// R. Ansari - 2002
4// LAL (Orsay) / IN2P3-CNRS DAPNIA/SPP (Saclay) / CEA
5
6#include "machdefs.h"
[2085]7#include <stdio.h>
[2103]8#include <iostream.h>
[2096]9#include <strings.h>
[2080]10#include <math.h>
[2088]11#include "piaxes.h"
[2080]12
[2138]13//++
14// Class PIAxes
15// Lib PI
16// include piaxes.h
17//
18// Classe gestionnaire de tracé d'axes. A utiliser dans
19// un objet PIDrawer.
20//--
21//++
22// Links Voir
23// PIDrawer
24//--
25
26//++
27// Titre Constructeurs et méthodes
28//--
29
30
[2091]31inline void dble_SWAP(double& a,double& b) {double tmp=a; a=b; b=tmp;}
[2080]32
[2138]33//++
34// PIAxes()
35// Constructeur.
36//--
37
[2080]38/* --Methode-- */
39PIAxes::PIAxes()
40{
41}
42
43/* --Methode-- */
44PIAxes::~PIAxes()
45{
46}
47
[2138]48//++
49// void DrawXYAxes(PIGraphicUC* g, PIGraphicAtt& gratt, unsigned int flags, bool afsz)
50// Trace les axes en utilisant les limites de l'objet PIGraphicUC.
51// "flags" spécifie les attributs d'axes. Constantes prédéfinies:
52//| kStdAxes : Axes passant par le centre
53//| kBoxAxes : Axes entourant le tracé
54//| kIntTicks, kExtTicks
55//| kMajTicks, kMinTicks
56//| kAxesDflt = kStdAxes | kTicks | kLabels
57//| kGridOn, kAxesNone
58// Si "afsz == true", la taille de fonte est choisie automatiquement.
59// void DrawXYAxes(PIGraphicUC* g, PIGraphicAtt& gratt, unsigned int flags, bool afsz, \
60// double xmin, double xmax, double ymin, double ymax)
61// Tracé d'axes avec spécification des limites d'axes.
62//--
63
[2080]64/* --Methode-- */
65void PIAxes::DrawXYAxes(PIGraphicUC* g, PIGraphicAtt& gratt,
66 unsigned int flags, bool afsz)
67{
68 PIGrCoord xmin, xmax, ymin, ymax;
69 g->GetGrSpace(xmin, xmax, ymin, ymax);
70 DrawXYAxes(g, gratt, flags, afsz, (double)xmin, (double)xmax,
71 (double)ymin, (double)ymax);
72}
73
74/* --Methode-- */
75void PIAxes::DrawXYAxes(PIGraphicUC* g, PIGraphicAtt& gratt,
76 unsigned int flags, bool afsz,
77 double xmin, double xmax, double ymin, double ymax)
78{
79 Setup(g, xmin, xmax, ymin, ymax);
80 // g->NoClip();
81
82 if (gratt.GetLineAtt() == PI_NotDefLineAtt) g->SelLine(PI_ThinLine);
83 else g->SelLine(gratt.GetLineAtt());
84 if (gratt.GetColor() == PI_NotDefColor) g->SelForeground(PI_Black);
85 else g->SelForeground(gratt.GetColor());
86
87 if(afsz) {
88 double fsz = xMajTickLen*3.5;
89 g->SelFontSz(fsz);
90 }
91
92 if (flags & kStdAxes) {
93
94 // Les axes
95
96 g->DrawLine(xMin, (yMin+yMax)/2., xMax, (yMin+yMax)/2.);
97 g->DrawLine((xMin+xMax)/2., yMin, (xMin+xMax)/2., yMax);
98
99 // La grille en pointilles
100
101 if (flags & kGridOn) DrawGrid(g);
102
103 // Les ticks majeurs
104
105 if (flags & kMajTicks) {
[2088]106 DrawHTicks(g, (yMin+yMax)/2., xMajTickLen, xMajTickLen, xMajTicks);
107 DrawVTicks(g, (xMin+xMax)/2., yMajTickLen, yMajTickLen, yMajTicks);
[2080]108 }
109
110 // Les ticks mineurs
111
112 if (flags & kMinTicks) {
[2088]113 DrawHTicks(g, (yMin+yMax)/2., xMinTickLen, xMinTickLen, xMinTicks);
114 DrawVTicks(g, (xMin+xMax)/2., yMinTickLen, yMinTickLen, yMinTicks);
[2080]115 }
116
117 // Les labels
118
119 if (flags & kLabels) {
120 if (!aYdir)
[2088]121 DrawHLabels(g, (yMin+yMax)/2.-xMajTickLen*2, xMajTicks, PI_VerticalTop);
[2080]122 else
[2088]123 DrawHLabels(g, (yMin+yMax)/2.+xMajTickLen*2, xMajTicks, PI_VerticalTop);
[2080]124 if (!aXdir)
[2088]125 DrawVLabels(g, (xMin+xMax)/2.-yMajTickLen*2, yMajTicks, PI_HorizontalRight);
[2080]126 else
[2088]127 DrawVLabels(g, (xMin+xMax)/2.+yMajTickLen*2, yMajTicks, PI_HorizontalRight);
[2080]128 }
129
130 }
131
132 if (flags & kBoxAxes) {
133
134 // La boite
135
136 g->DrawLine(xMin, yMin, xMax, yMin);
137 g->DrawLine(xMax, yMin, xMax, yMax);
138 g->DrawLine(xMax, yMax, xMin, yMax);
139 g->DrawLine(xMin, yMax, xMin, yMin);
140
141 // Longueur des ticks
142
143 double extXMajTickLen = flags&kExtTicks ? xMajTickLen : 0;
144 double intXMajTickLen = flags&kIntTicks ? xMajTickLen : 0;
145 double extXMinTickLen = flags&kExtTicks ? xMinTickLen : 0;
146 double intXMinTickLen = flags&kIntTicks ? xMinTickLen : 0;
147 double extYMajTickLen = flags&kExtTicks ? yMajTickLen : 0;
148 double intYMajTickLen = flags&kIntTicks ? yMajTickLen : 0;
149 double extYMinTickLen = flags&kExtTicks ? yMinTickLen : 0;
150 double intYMinTickLen = flags&kIntTicks ? yMinTickLen : 0;
151
152 // La grille en pointilles
153
154 if (flags & kGridOn) DrawGrid(g);
155
156 // Les ticks majeurs
157
158 if (flags & kMajTicks) {
[2088]159 DrawHTicks(g, yMin, intXMajTickLen, extXMajTickLen, xMajTicks);
160 DrawHTicks(g, yMax, extXMajTickLen, intXMajTickLen, xMajTicks);
161 DrawVTicks(g, xMin, extYMajTickLen, intYMajTickLen, yMajTicks);
162 DrawVTicks(g, xMax, intYMajTickLen, extYMajTickLen, yMajTicks);
[2080]163 }
164
165 // Les ticks mineurs
166
167 if (flags & kMinTicks) {
[2088]168 DrawHTicks(g, yMin, intXMinTickLen, extXMinTickLen, xMinTicks);
169 DrawHTicks(g, yMax, extXMinTickLen, intXMinTickLen, xMinTicks);
170 DrawVTicks(g, xMin, extYMinTickLen, intYMinTickLen, yMinTicks);
171 DrawVTicks(g, xMax, intYMinTickLen, extYMinTickLen, yMinTicks);
[2080]172 }
173
174
175 // Les labels
176
177 if (flags & kLabels) {
178 if (!aYdir) {
[2088]179 DrawHLabels(g, g->DeltaUCY(yMin, -xMajTickLen*2), xMajTicks, PI_VerticalTop);
[2080]180 }
181 else {
[2088]182 DrawHLabels(g, g->DeltaUCY(yMax, xMajTickLen*2), xMajTicks, PI_VerticalTop);
[2080]183 }
184 if (!aXdir) {
[2088]185 DrawVLabels(g, g->DeltaUCX(xMin, -yMajTickLen*2), yMajTicks, PI_HorizontalRight);
[2080]186 }
187 else {
[2088]188 DrawVLabels(g, g->DeltaUCX(xMax, yMajTickLen*2), yMajTicks, PI_HorizontalRight);
[2080]189 }
190 }
191 }
192 g->Clip();
193
194}
195
196/* --Methode-- */
197void PIAxes::Setup(PIGraphicUC* g, double xmin, double xmax,
198 double ymin, double ymax)
199{
200
201 xMin = xmin; xMax = xmax;
202 yMin = ymin; yMax = ymax;
203
204 aXdir = g->isAxeXDirRtoL();
205 aYdir = g->isAxeYDirUpDown();
206 aXlog = g->isLogScaleX();
207 aYlog = g->isLogScaleY();
208
[2091]209 int ntick_x = (aXlog) ? 10 : 10;
210 if(aXlog) BestTicksLog(xMin,xMax,ntick_x,xMajTicks,xMinTicks);
211 else BestTicks(xMin,xMax,ntick_x,xMajTicks,xMinTicks);
[2080]212
[2091]213 int ntick_y = (aYlog) ? 12 : 12;
214 if(aYlog) BestTicksLog(yMin,yMax,ntick_y,yMajTicks,yMinTicks);
215 else BestTicks(yMin,yMax,ntick_y,yMajTicks,yMinTicks);
[2080]216
217 yMajTickLen = (xMax-xMin)/100;
218 yMinTickLen = (xMax-xMin)/250;
219 xMajTickLen = (yMax-yMin)/100;
220 xMinTickLen = (yMax-yMin)/250;
221}
222
223
224/* --Methode-- */
225void PIAxes::DrawHTicks(PIGraphicUC* g, double y, double tickUp,
[2088]226 double tickDown, vector<double>& xticks)
[2080]227{
[2091]228 if(xticks.size()==0) return;
[2088]229 for(unsigned int i=0;i<xticks.size();i++) {
[2091]230 if(xticks[i]<xMin) continue;
[2088]231 if(xticks[i]>xMax) break;
232 g->DrawLine(xticks[i],g->DeltaUCY(y,-tickDown),xticks[i],g->DeltaUCY(y,tickUp));
233 }
[2080]234}
235
236/* --Methode-- */
237void PIAxes::DrawVTicks(PIGraphicUC* g, double x, double tickLeft,
[2088]238 double tickRight, vector<double>& yticks)
[2080]239{
[2091]240 if(yticks.size()==0) return;
[2088]241 for(unsigned int i=0;i<yticks.size();i++) {
[2091]242 if(yticks[i]<yMin) continue;
[2088]243 if(yticks[i]>yMax) break;
244 g->DrawLine(g->DeltaUCX(x,-tickLeft),yticks[i],g->DeltaUCX(x,tickRight),yticks[i]);
245 }
[2080]246}
247
248/* --Methode-- */
[2088]249void PIAxes::DrawHLabels(PIGraphicUC* g, double y, vector<double>& xticks, unsigned long just)
[2080]250{
[2091]251 if(xticks.size()==0) return;
[2080]252
[2091]253 // Choix du bon format pour les labels des axes
254 string format; double xstep;
255 int npuiss = Le_Bon_Format(xticks,format,xstep);
256 double fac=(npuiss!=0)? fac=pow(10.,(double)npuiss): 1.;
[2080]257
[2091]258 char label[64];
259 double dum,xpixdeb,xpixfin,largpix;
260 g->UC2GrC(xMin-2.*(xMax-xMin),y,xpixfin,dum);
[2088]261 for(unsigned int i=0;i<xticks.size();i++) {
[2091]262 if(xticks[i]<xMin) continue;
[2088]263 if(xticks[i]>xMax) break;
[2080]264 //Attention erreur d'arrondi x->0 (on code 5.1698e-26 au lieu de 0)
[2088]265 double xx = (fabs(xticks[i]/xstep)<1.e-5) ? 0.: xticks[i];
[2091]266 sprintf(label,format.c_str(),xx/fac); Arrange_Label(label);
[2080]267 double largeur = g->CalcStringWidth(label);
[2091]268 g->DUC2GrC(largeur,0.,largpix,dum);
269 g->UC2GrC(xticks[i],y,xpixdeb,dum); xpixdeb -= largpix/2.;
270 //cout<<"xticks="<<xticks[i]<<" largpix="<<largpix
271 // <<" xpixdeb="<<xpixdeb<<" xpixfin="<<xpixfin<<endl;
272 if((aXdir && xpixdeb<xpixfin) || (!aXdir && xpixdeb>xpixfin)) {
[2088]273 g->DrawString(xticks[i],y,label,PI_HorizontalCenter|just);
[2091]274 xpixfin = xpixdeb + 1.1*largpix;
[2080]275 }
276 }
277
[2091]278 if(npuiss!=0) {
[2080]279 PIGrCoord asc,desc;
280 double h = g->GetFontHeight(asc,desc);
[2091]281 if((aYdir && (just&PI_VerticalBottom)) || (!aYdir && (just&PI_VerticalTop))) h=-h;
[2080]282 double xm = (aXdir)? xMin: xMax;
283 double ym = g->DeltaUCY(y,1.5*h);
284 sprintf(label,"%d",npuiss);
285 g->DrawCompString(xm,ym,"x 10",label,NULL,PI_HorizontalCenter|just);
286 }
287
288}
289
290/* --Methode-- */
[2088]291void PIAxes::DrawVLabels(PIGraphicUC* g, double x, vector<double>& yticks, unsigned long just)
[2080]292{
[2091]293 if(yticks.size()==0) return;
[2080]294
295 // Choix du bon format pour les labels des axes;
[2091]296 string format; double ystep;
297 int npuiss = Le_Bon_Format(yticks,format,ystep);
298 double fac=(npuiss!=0)? fac=pow(10.,(double)npuiss): 1.;
[2080]299
[2091]300 char label[64];
301 PIGrCoord asc,desc;
302 double dum,ypixdeb,ypixfin,hautpix,hauteur=g->GetFontHeight(asc,desc);
303 g->DUC2GrC(0.,hauteur,dum,hautpix);
304 g->UC2GrC(x,yMin-2.*(yMax-yMin),dum,ypixfin);
[2088]305 for(unsigned int i=0;i<yticks.size();i++) {
[2091]306 if(yticks[i]<yMin) continue;
[2088]307 if(yticks[i]>yMax) break;
308 double yy = (fabs(yticks[i]/ystep)<1.e-5) ? 0.: yticks[i];
[2091]309 sprintf(label,format.c_str(),yy/fac); Arrange_Label(label);
310 g->UC2GrC(x,yticks[i],dum,ypixdeb); ypixdeb -= hautpix/2.;
311 // -- Attention: ypix=0 est en haut de l'ecran
312 // (ypix croissants vers le bas de l'ecran)
313 // donc bien que yMin<yMax on a yMinPix>yMaxPix
314 //cout<<"yticks="<<yticks[i]<<" hautpix="<<hautpix
315 // <<" ypixdeb="<<ypixdeb<<" ypixfin="<<ypixfin<<endl;
316 if((aYdir && ypixdeb>ypixfin) || (!aYdir && ypixdeb<ypixfin)) {
317 g->DrawString(x,yticks[i],label,PI_VerticalCenter|just);
318 ypixfin = ypixdeb + 1.1*hautpix;
319 }
[2080]320 }
321
[2091]322 if(npuiss!=0) {
323 if(aYdir) hauteur = -hauteur;
324 double ym = (aYdir)? yMin: yMax; ym = g->DeltaUCY(ym,hauteur);
[2080]325 sprintf(label,"%d",npuiss);
326 g->DrawCompString(x,ym,"x 10",label,NULL,PI_VerticalBottom|just);
327 }
328
329}
330
331/* --Methode-- */
332void PIAxes::DrawGrid(PIGraphicUC* g)
333{
334 PILineAtt savlineatt = g->GetLineAtt();
335 g->SelLine(PI_ThinDottedLine);
336
[2088]337 if(xMajTicks.size()>0)
338 for(unsigned int i=0;i<xMajTicks.size();i++) {
339 if(xMajTicks[i]>xMax) break;
340 g->DrawLine(xMajTicks[i], yMin, xMajTicks[i], yMax);
341 }
[2080]342
[2088]343 if(yMajTicks.size()>0)
344 for(unsigned int i=0;i<yMajTicks.size();i++) {
345 if(yMajTicks[i]>yMax) break;
346 g->DrawLine(xMin, yMajTicks[i], xMax, yMajTicks[i]);
347 }
[2080]348
349 g->SelLine(savlineatt);
350}
351
[2091]352////////////////////////////////////////////////////////////////////////
353//////////////////// METHODES STATIQUES ////////////////////////////////
354////////////////////////////////////////////////////////////////////////
[2080]355/* --Methode-Static-- */
[2115]356void PIAxes::ReSizeMinMax(bool axelog,double& vmin,double& vmax,double garde)
357// Calcul du min et du max du display a partir des valeurs min et max a plotter
358{
359 if(garde<0. || garde>=1.) garde = 0.025;
[2119]360 // cout<<"ReSizeMinMax[log="<<axelog<<",garde="<<garde<<"] vmin="<<vmin<<" vmax="<<vmax<<endl;
[2115]361 // Cas d'une echelle lineaire
362 if(!axelog || vmax<=0.) {
363 double dv = garde*(vmax-vmin);
364 vmin -= dv;
365 vmax += dv;
366 }
367
368 // Cas d'une echelle log avec un range raisonnable
369 else if(vmin>0.) {
370 double dv = pow(vmax/vmin,garde);
371 vmin /= dv;
372 vmax *= dv;
373 }
374
375 // Cas d'une echelle log avec un range de-raisonnable
376 else if(vmin<=0.) {
377 if(vmin<0.) vmin += garde*vmin;
378 if(vmax==1.) vmax = 1.+garde;
379 if(vmax>1.) vmax = pow(vmax,1.+garde);
380 else vmax = pow(vmax,1.-garde);
381 }
382
[2119]383 // cout<<" vmin="<<vmin<<" vmax="<<vmax<<endl;
[2115]384}
385
386/* --Methode-Static-- */
[2080]387void PIAxes::BestTicks(double xmin,double xmax,int nticks
[2088]388 ,vector<double>& majticks,vector<double>& minticks)
[2080]389// *** Calcul de l'intervalle entre les ticks et de la valeur du premier tick
[2091]390// pour un axe lineaire
[2080]391{
[2091]392 if(nticks<=0) nticks = 1;
393
394 double d=xmax-xmin; if(d<1.e-100) d=1.e-100;
[2088]395 double ld = log10(d);
396 double fld = floor( ((ld<0.)? -ld: ld) );
397 double del,del0;
[2091]398 fld = (ld>=0.)? fld-2.: -(fld+2.);
399 del0 = del = pow(10.,fld);
[2088]400 // *** Intervalle entre les ticks
401 // xmin xmax d ld fld -->fld del0
[2091]402 // 1 1500 1499 3.17 3 1 10^1
403 // 1 9500 9499 3.98 3 1 10^1
404 // 1 1.005 0.005 -2.3 3 -5 10^-5
405 // 1 1.995 0.995 -0.0022 1 -3 10^-3
406 // - Et recherche de la valeur del={del0,2*del0,...,20*del0,...}
407 // telle que "nticks*del" soit le plus petit nombre ">=xmax-xmin"
408 double fac[9] = {2.,5.,10.,20.,50.,100.,200.,500.,1000.};
409 for(int k=0;k<9;k++) {
410 //cout<<"BestTicks: "<<k<<" del="<<del<<" d/del="<<d/del<<"<"<<nticks<<endl;
411 if(d/del < (double)nticks) break;
412 del=fac[k]*del0;
413 }
[2088]414 double steptick=del;
415 //*** Valeur du premier tick
[2091]416 majticks.resize(0);
417 double xfirsttick = floor(fabs(xmin)/steptick)*steptick;
418 if(xmin<0.) xfirsttick *= -1.;
[2088]419 if(xfirsttick<xmin) xfirsttick += steptick;
[2091]420 while(xfirsttick<=xmax+steptick/10.)
421 {majticks.push_back(xfirsttick); xfirsttick+= steptick;}
[2088]422 //*** Gestion des ticks mineurs
[2091]423 minticks.resize(0);
424 if(majticks.size()>1) {
425 double steptickmin = steptick/5.;
426 double xfirsttickmin = majticks[0];
427 while(xfirsttickmin<=xmax+steptickmin/10.)
428 {minticks.push_back(xfirsttickmin); xfirsttickmin+= steptickmin;}
429 }
[2080]430}
[2091]431/* --Methode-Static-- */
432void PIAxes::BestTicksLog(double xmin,double xmax,int nticks
433 ,vector<double>& majticks,vector<double>& minticks)
434// *** Calcul des ticks pour un axe logarithmique
435{
436 if(nticks<=0) nticks = 1;
437 //cout<<"BestTicksLog: xmin="<<xmin<<" xmax="<<xmax<<" nticks="<<nticks<<endl;
[2080]438
[2115]439 // Si xmax<=0, on garde BestTicks
440 if(xmax<=0. ) {
441 //cout<<"Choix de BestTicks car xmax="<<xmax<<endl;
[2091]442 BestTicks(xmin,xmax,nticks,majticks,minticks);
443 return;
444 }
445
[2115]446 int dmin, dmax=int(floor(log10(xmax)));
447 if(xmin>0.) {
448 // Dynamique trop faible, on garde BestTicks
449 if(xmax/xmin<5.) {
450 //cout<<"Choix de BestTicks car xmax/xmin="<<xmax/xmin<<" <5"<<endl;
[2116]451 BestTicks(xmin,xmax,nticks,majticks,minticks);
[2115]452 return;
453 }
454 dmin=int(floor(log10(xmin)));
455 } else {
456 if(dmax>3) dmin = dmax/3;
457 else dmin = dmax-1;
458 }
[2091]459 if(dmax==dmin) dmax++; else if(dmax<dmin) dmax=dmin+1;
460 int inc = (dmax-dmin+1)/nticks; if(inc<1) inc=1;
461 //cout<<" dmin="<<dmin<<" dmax="<<dmax<<" inc="<<inc<<endl;
462
463 majticks.resize(0);
[2122]464 {for(int i=dmin;i<=dmax;i+=inc) {
[2091]465 double x = pow(10.,(double)i);
466 if(x<xmin || x>xmax) continue;
467 majticks.push_back(x);
[2122]468 }}
[2091]469 //cout<<"majticks.size()="<<majticks.size()<<endl;
470
[2115]471 // Pas de puissance de 10 dans l'intervalle on garde BestTicks
[2091]472 if(majticks.size()==0) {
473 BestTicks(xmin,xmax,nticks,majticks,minticks);
474 return;
475 }
476
477 // Pas suffisamment de ticks majeurs
478 if((int)majticks.size()<=nticks/2) {
479 int nins = nticks/(majticks.size()+1);
480 if(nins<=0) nins=1;
481 //cout<<"nins="<<nins<<endl;
482 // Sequence judicieuse pour remplir les ticks manquants
483 // nins = 1 on insere 3
484 // 2 2 5
485 // 3 2 4 6
486 // 4 1.5 2 4 6
487 // >=5 on reste au cas precedent
488 double seqmaj[4][4] = {{3.,0,0,0},{2.,5.,0,0},{2.,4.,6.,0},{1.5,2.,4.,6.}};
489 if(nins>4) nins=4;
490 vector<double> tmp;
[2122]491 {for(unsigned int i=0;i<=majticks.size();i++) {
[2091]492 double xt;
[2122]493 if(i<majticks.size()) xt = majticks[i]/10.;
494 else xt = majticks[i-1];
[2091]495 for(int n=0;n<nins;n++) {
496 double xins = seqmaj[nins-1][n]*xt;
497 if(xins<xmin || xins>xmax) continue;
498 tmp.push_back(xins);
499 }
[2122]500 if(i<majticks.size()) tmp.push_back(majticks[i]);
501 }}
[2091]502 majticks = tmp;
503 }
504 //cout<<"...majticks.size()="<<majticks.size()<<endl;
505
[2115]506 // Les ticks mineurs
[2091]507 minticks.resize(0);
[2122]508 {for(unsigned int i=0;i<majticks.size()-1;i++) {
[2091]509 double dx = (majticks[i+1]-majticks[i])/10.;
510 minticks.push_back(majticks[i]);
511 for(int j=2;j<=8;j+=2) {
512 double x = majticks[i] + j*dx;
513 if(x<xmin || x>xmax) continue;
514 minticks.push_back(x);
515 }
[2122]516 }}
[2091]517 minticks.push_back(majticks[majticks.size()-1]);
518 //cout<<"...minticks.size()="<<minticks.size()<<endl;
519
[2115]520 // Si on a xmin<=0., on insere zero dans les ticks majeurs
521 if(xmin<=0.) {
522 vector<double> tmp = majticks;
523 majticks.resize(0); majticks.push_back(0.);
[2122]524 for(unsigned int i=0;i<tmp.size();i++) majticks.push_back(tmp[i]);
[2115]525 //cout<<"...xmin="<<xmin<<"<=0. add majticks[0]="<<majticks[0]<<endl;
526 }
527
[2091]528}
529
[2080]530/* --Methode-Static-- */
531int PIAxes::BonFormatAxes(double xmin,double xmax,double xstep
[2116]532 ,string& format,int typf,int add_digit)
[2080]533// *** Calcul format optimal pour ecrire les labels numeriques des axes:
534// ---- Input
535// . xmin,xmax : limites du plot sur l'axe considere.
536// . xstep : distance entre les ticks.
537// . add_digit : nombre de digits a ajouter au nombre de digits minimum.
538// . typf : type de format en sortie
539// 0 : format optimum %-nn.mme ou %-nn.mmf selon valeurs
540// 1 : format %-nn.mme
541// 2 : format %-nn.mmf pour imprimer x/10^npuiss
[2116]542// tel que x/10^npuiss soit entre [0,10]
543// 3 : format %-nn.mmf
[2080]544// ---- Output
545// . format : le format d'impression
546// ---- Return:
[2116]547// Si typ=0 ou 1 ou 3
[2080]548// "ndig" : nombre de digits necessaires pour distinguer
549// les valeurs xmin+k*dx (<=xmax)
550// Si typ=2
551// "npuiss" : tel que x/10^npuiss soit entre 0 et 10
552// Dans ce cas le format est celui qui imprime x/10^npuiss
553{
554 format = "%-5g"; // format par default
555 if(xmin>=xmax) {if(typf==2) return 0; else return -1;}
556
557 if(xstep<=0. || xstep>xmax-xmin) xstep = xmax-xmin;
558
559 double axmin=fabs(xmin), axmax=fabs(xmax);
560 if(axmin>axmax) dble_SWAP(axmin,axmax);
561
562 double l10amax = log10(axmax), l10xstep = log10(xstep);
563 int il10amax = int(floor(l10amax));
564
565 // choix du type de format
566 char ftype = 'e';
567 int npuiss = 0;
568 if(typf==2) {
[2116]569 npuiss = il10amax-1; // nombre entre [0,10]
570 //npuiss = il10amax; // nombre entre [0,1]
[2080]571 if(npuiss<-300 || npuiss>300) {
572 ftype='e'; npuiss=0;
573 } else {
574 // On recalcule les valeurs de decision pour axmax/10^npuiss, xstep/10^npuiss
575 l10amax -= (double)npuiss; l10xstep -= (double)npuiss;
576 il10amax = int(floor(l10amax));
577 ftype = 'f';
578 }
579 } else if(typf==1) {
580 ftype='e';
[2116]581 } else if(typf==3) {
582 ftype='f';
[2080]583 } else {
584 ftype='e';
585 // On evite d'ecrire +a.bbbe+ccc -> format %f
586 // Ex: 1.2345e+2 -> 123.45 / -1.2345e+2 -> -123.45
587 // 1.2345e-1 -> 0.12345 / -1.2345e-1 -> -0.12345
588 if((axmin>=1e-4 || axmin==0.) && axmax<1e4) ftype='f';
589 }
590
591 //printf("BonFormatAxes[npuiss=%d]: xmin=%-21.14e xmax=%-21.14e\n",npuiss,xmin,xmax);
592 //printf(" xstep=%-21.14e log10(xstep/10^%d)=%g\n",xstep,npuiss,l10xstep);
593 //printf(" axmax=%-21.14e log10(axmax/10^%d)=%g diff=%g\n"
594 // ,axmax,npuiss,l10amax,l10amax-l10xstep);
595
596 // Nombre de digits necessaires pour ecrire axmax et xstep
597 int ndig = il10amax - int(floor(l10xstep));
598 if(ndig<0) ndig *= -1; ndig += 1;
599 //printf("ndig=%d",ndig);
600
601 // Add more digits (or suppress digits)
602 ndig += add_digit; if(ndig<0) ndig=0;
603 //printf(" + %d ==> ndig=%d\n",add_digit,ndig);
604
605 // Calcul du bon format
606 char str[16];
607 if(ftype=='f') { // Calcul du format %-nn.mmf
608 int mm=-1, nn;
609 if(il10amax<0) { // +0.12345 +0.0012345 +0.0012345 ...
610 mm = ndig - il10amax - 1; nn = mm+3;
611 } else { // +1.2345 +12.345 +123.45 ...
612 mm = ndig - il10amax - 1; nn = ndig+2;
613 }
614 //printf("format %%f : mm=%d nn=%d\n",mm,nn);
615 if(mm<0.) mm=0; if(nn<mm+3) nn=mm+3;
616 sprintf(str,"%%-%d.%df",nn,mm);
617 } else if(ftype=='e') { // Calcul du format %-nn.mme
618 // +d.<--ddd-->e+123
619 // 1 2 34567 ==> nn=ndig+7 mm=ndig-1
620 sprintf(str,"%%-%d.%de",ndig+7,ndig-1);
621 }
622
623 format = str;
624 //printf("format=[%s]\n",format.c_str());
625
626 if(typf==2) return npuiss;
627 return ndig;
628}
629
[2091]630/* --Methode-- */
631int PIAxes::Le_Bon_Format(vector<double>& xticks,string& format,double& xstep)
632// Methode static de decision du bon format
633// Decide quel format est le mieux adapte pour ecrire les labels des axes
634// Decide si une puissance de 10 doit etre deportee en bout d'axe
635// - Input:
636// xticks : vecteur des ticks a ecrire (calcule par BestTicks)
637// - Output:
638// format : format a utiliser
639// xstep : step entre 2 graduations
640// - Return:
641// npuiss : si format choisit avec ecriture
642// avec label des puissances de 10 deporte
643// 0 : sinon
644{
645 format="%g"; xstep=1.;
646 if(xticks.size()<=1) return 0;
647
[2116]648 // On decide du format
[2091]649 xstep=xticks[1]-xticks[0];
650 int npuiss = BonFormatAxes(xticks[0],xticks[xticks.size()-1],xstep,format,2,1);
[2116]651 if(npuiss>=-2 && npuiss<=2) {
[2091]652 npuiss = 0;
[2116]653 BonFormatAxes(xticks[0],xticks[xticks.size()-1],xstep,format,3,1);
[2091]654 }
[2116]655
[2091]656 return npuiss;
657}
658
[2088]659void PIAxes::Arrange_Label(char *label)
[2091]660// --- Mise en forme optimale du label numerique
[2116]661// Enleve les blancs, les zeros, le point et les e00
662// inutiles a la fin d'un label
[2088]663{
664 size_t lenl=strlen(label);
665 if(lenl==0) return;
666
667 // --- On enleve les blancs et plus au debut du label
668 if(label[0]==' ' || label[0]=='+') {
669 char *str=new char[lenl+2];
670 strcpy(str,label);
671 unsigned i=0;
672 for(i=0;i<lenl;i++) if(str[i]!=' ' && str[i]!='+') break;
673 strcpy(label,&str[i]);
674 delete [] str;
675 lenl=strlen(label);
676 if(lenl==0) return;
677 }
678
679 // --- On enleve les blancs a la fin du label
680 if(label[lenl-1]==' ') {
[2096]681 for(int i=lenl-1;i>=0;i--) {
[2088]682 if(label[i]!=' ') break;
683 label[i]='\0';
684 }
685 lenl=strlen(label);
686 }
687
688 // --- On enleve les e... E... non-significatifs
689 // ex: a.be-zzz a.be+zzz a.bezzz avec zzz=0,00,000,...
690 // Attention on n'enleve pas si: a.be+10
691 // Attention on ne fait rien si: e+10
692 char* e=index(label,'e');
693 if(e==NULL) e=index(label,'E');
694 if(e) {
[2096]695 for(int i=lenl-1;i>=0;i--) {
[2088]696 if(isdigit(label[i]) && label[i]!='0') break;
697 if(label[i]=='e' || label[i]=='E')
698 {label[i]='\0'; lenl=strlen(label); break;}
699 }
700 }
701
702 // --- On enleve les zeros non-significatifs a la fin du label
703 // On enleve des zeros ou le point si: ab. ab.czzz avec zzz=0,00,000,...
704 // Attention on n'enleve pas de zeros si: abzzz
705 // Attention a ne pas enlever des zeros si on a ab.ccce+a0
706 // Attention on traite 0eaaa -> 0
707 if(index(label,'.')==NULL) return; // Recherche d'un point
708 string stre;
709 if(e) {if(e==label) return; stre=e; *e='\0'; lenl=strlen(label);}
[2122]710 {for(int i=lenl-1;i>=0;i--) {
[2088]711 if(label[i]=='0') label[i]='\0';
712 else if(label[i]=='.') {
713 if(i>0) label[i]='\0';
714 else {
715 // Attention: ".e+10" -> "1e+10" MAIS "." -> "0"
716 if(e) strcpy(label,"1"); else strcpy(label,"0");
717 }
718 break;
719 }
720 else break; // Ni un point ni un zero
[2122]721 }}
[2088]722 if(e) {
723 if(strlen(label)==1) if(label[0]=='0') return;
724 strcat(label,stre.c_str());
725 }
726
727}
Note: See TracBrowser for help on using the repository browser.