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

Last change on this file since 2322 was 2322, checked in by cmv, 23 years ago
  • passage xxstream.h en xxstream
  • compile avec gcc_3.2, gcc_2.96 et cxx En 3.2 le seek from ::end semble marcher (voir Eval/COS/pbseekios.cc)

rz+cmv 11/2/2003

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