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

Last change on this file since 2516 was 2516, checked in by cmv, 22 years ago

GetDistanceToPoint et preparation des axes centres avec x0,y0

quelconques cmv 17/03/04

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