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

Last change on this file since 2349 was 2349, checked in by ansari, 23 years ago

Correction-amelioration de trace des ticks d'axes - Possibilites
de specifier ticks interne ou externes, ainsi que taille des ticks
et taille de fonte pour autofontsize

Reza - 18 Mars 2003

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