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

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

intro de ConfigureAxesCenter pour option axescenter=x0,y0 cmv 19/03/04

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