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

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

petite modif format ecriture nombres pour labels axes (%e au lieu de %f) pour nombre trop grand ou trop petit - Reza 10/06/2008

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