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

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

Amelioration gestion AutoFontSize - mis ds la classe PIDrawer - Le flag mAFsz et mFontSzF peut donc etre utilise pour autofontsize du trace des axes, mais aussi des autres drawers - Reza , 24/12/2008

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