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

Last change on this file since 2091 was 2091, checked in by cmv, 23 years ago
  • gestion des ticks et des labels pour les axes log
  • gestion plus precise des ecriture de labels

--> chgnt PIVERSION = 3.69 cmv 13/07/2002

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