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

Last change on this file since 3562 was 3562, checked in by ansari, 17 years ago

Amelioration de la logique AutoFontSize ds PIDrawer avec ajout valeur globale par defaut et controle possible avec la variable d'environnement PIDEFAFSZFRAC

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