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

Last change on this file since 2797 was 2797, checked in by ansari, 20 years ago

Corrections liees au trace des axes et caption (axes centres) et correction pour Refresh de DrwOptionStringWindow - Reza 3 Juin 2005

File size: 27.5 KB
Line 
1// Module PI : Peida Interactive PIAxes
2// Methodes de trace des axes
3// R. Ansari - 2002
4// LAL (Orsay) / IN2P3-CNRS DAPNIA/SPP (Saclay) / CEA
5
6#include "sopnamsp.h"
7#include "machdefs.h"
8#include <stdio.h>
9#include <iostream>
10#include <strings.h>
11#include <math.h>
12#include "piaxes.h"
13
14//++
15// Class PIAxes
16// Lib PI
17// include piaxes.h
18//
19// Classe gestionnaire de tracé d'axes. A utiliser dans
20// un objet PIDrawer.
21//--
22//++
23// Links Voir
24// PIDrawer
25//--
26
27//++
28// Titre Constructeurs et méthodes
29//--
30
31
32inline void dble_SWAP(double& a,double& b) {double tmp=a; a=b; b=tmp;}
33
34//++
35// PIAxes()
36// Constructeur.
37//--
38
39/* --Methode-- */
40PIAxes::PIAxes()
41{
42 ConfigureTicks();
43 ConfigureAutoFontSize();
44 ConfigureAxesCenter();
45 setupDone = false;
46}
47
48/* --Methode-- */
49PIAxes::~PIAxes()
50{
51}
52
53//++
54// void DrawXYAxes(PIGraphicUC* g, PIGraphicAtt& gratt, \
55// unsigned int flags=kAxesDflt, bool afsz=true)
56// Trace les axes en utilisant les limites de l'objet PIGraphicUC.
57// "flags" spécifie les attributs d'axes. Constantes prédéfinies:
58//| kCentAxes : Axes passant par le centre
59//| kBoxAxes : Axes entourant le tracé
60//| kIntTicks, kExtTicks
61//| kMajTicks, kMinTicks
62//| kLabelsH, kLabelsV, kLabels
63//| kAxesDflt = kStdAxes =
64//| kBoxAxes | kTicks | | kIntTicks | kLabels
65//| kGridOn, kAxesNone
66// Si "afsz == true", la taille de fonte est choisie automatiquement.
67//
68// void DrawXYAxes(PIGraphicUC* g, PIGraphicAtt& gratt, \
69// double xmin, double xmax, double ymin, double ymax, \
70// unsigned int flags=kAxesDflt, bool afsz=true)
71// Tracé d'axes avec spécification des limites d'axes.
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.
77//--
78
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);
85 DrawXYAxes(g, gratt, (double)xmin, (double)xmax,
86 (double)ymin, (double)ymax, flags, afsz);
87}
88
89/* --Methode-- */
90void PIAxes::DrawXYAxes(PIGraphicUC* g, PIGraphicAtt& gratt,
91 double xmin, double xmax, double ymin, double ymax,
92 unsigned int flags, bool afsz)
93
94{
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
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) {
109 double fsz = (yMax-yMin)*fontSz;
110 g->SelFontSz(fsz);
111 }
112
113 if (flags & kCentAxes) {
114
115 // Les axes
116 double x0axes = (xMin+xMax)/2., y0axes = (yMin+yMax)/2.;
117 if(axesCenter) {x0axes = axesCentX0; y0axes = axesCentY0;}
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 & kTicks) && (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 & kTicks) && (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 & kLabelsH) {
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 if (flags & kLabelsV) {
160 double declab = 2.*yMajTickLen;
161 if (!aXdir)
162 DrawVLabels(g, x0axes-declab, yMajTicks, PI_HorizontalRight);
163 else
164 DrawVLabels(g, x0axes+declab, yMajTicks, PI_HorizontalRight);
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
194 if (flags & kMajTicks) {
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);
199 }
200
201 // Les ticks mineurs
202
203 if (flags & kMinTicks) {
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);
208 }
209
210
211 // Les labels
212
213 if (flags & kLabelsH) {
214 double declab = xMajTickLen;
215 if (flags & kExtTicks) declab *= 2.;
216 if (!aYdir) {
217 DrawHLabels(g, g->DeltaUCY(yMin, -declab), xMajTicks, PI_VerticalTop);
218 }
219 else {
220 DrawHLabels(g, g->DeltaUCY(yMax, declab), xMajTicks, PI_VerticalTop);
221 }
222 }
223 if (flags & kLabelsV) {
224 double declab = yMajTickLen;
225 if (flags & kExtTicks) declab *= 2.;
226 if (!aXdir) {
227 DrawVLabels(g, g->DeltaUCX(xMin, -declab), yMajTicks, PI_HorizontalRight);
228 }
229 else {
230 DrawVLabels(g, g->DeltaUCX(xMax, declab), yMajTicks, PI_HorizontalRight);
231 }
232 }
233 }
234 g->Clip();
235
236}
237
238/* --Methode-- */
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
253 double fx,fy,fh;
254 if (flags&kBoxAxes) {
255 fh = -0.090*(yMax-yMin);
256 if (g->isAxeYDirUpDown()) fy = yMax;
257 else fy = yMin;
258 }
259 else {
260 fh = 0.04*(yMax-yMin);
261 if(axesCenter) fy = axesCentY0;
262 else fy = 0.5*(yMin+yMax);
263 if(fy<yMin || fy>yMax) fy = (yMin+yMax)/2.;
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(),
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
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;
292 }
293 else {
294 fh = 0.04*(xMax-xMin);
295 if(axesCenter) fx = axesCentX0;
296 else fx = 0.5*(xMin+xMax);
297 if(fx<xMin || fx>xMax) fx = (xMin+xMax)/2.;
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
307}
308
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
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
321//--
322
323/* --Methode-- */
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}
332
333/* --Methode-- */
334void PIAxes::ConfigureAutoFontSize(double fszf)
335{
336 if (fszf > 1.e-19) fontSz = fszf;
337}
338
339/* --Methode-- */
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-- */
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
361 // Reza - Mars 03 - Nb de ticks en parametres
362 int ntick_x = (aXlog) ? xNTicks : xNTicks;
363 if(aXlog) BestTicksLog(xMin,xMax,ntick_x,xMajTicks,xMinTicks);
364 else BestTicks(xMin,xMax,ntick_x,xMajTicks,xMinTicks);
365
366 int ntick_y = (aYlog) ? yNTicks : yNTicks;
367 if(aYlog) BestTicksLog(yMin,yMax,ntick_y,yMajTicks,yMinTicks);
368 else BestTicks(yMin,yMax,ntick_y,yMajTicks,yMinTicks);
369
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
375
376 setupDone = true;
377}
378
379
380/* --Methode-- */
381void PIAxes::DrawHTicks(PIGraphicUC* g, double y, double tickUp,
382 double tickDown, vector<double>& xticks)
383{
384 if(xticks.size()==0) return;
385 for(unsigned int i=0;i<xticks.size();i++) {
386 if(xticks[i]<xMin) continue;
387 if(xticks[i]>xMax) break;
388 g->DrawLine(xticks[i],g->DeltaUCY(y,-tickDown),xticks[i],g->DeltaUCY(y,tickUp));
389 }
390}
391
392/* --Methode-- */
393void PIAxes::DrawVTicks(PIGraphicUC* g, double x, double tickLeft,
394 double tickRight, vector<double>& yticks)
395{
396 if(yticks.size()==0) return;
397 for(unsigned int i=0;i<yticks.size();i++) {
398 if(yticks[i]<yMin) continue;
399 if(yticks[i]>yMax) break;
400 g->DrawLine(g->DeltaUCX(x,-tickLeft),yticks[i],g->DeltaUCX(x,tickRight),yticks[i]);
401 }
402}
403
404/* --Methode-- */
405void PIAxes::DrawHLabels(PIGraphicUC* g, double y, vector<double>& xticks, unsigned long just)
406{
407 if(xticks.size()==0) return;
408
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.;
413
414 char label[64];
415 double dum,xpixdeb,xpixfin,largpix;
416 g->UC2GrC(xMin-2.*(xMax-xMin),y,xpixfin,dum);
417 for(unsigned int i=0;i<xticks.size();i++) {
418 if(xticks[i]<xMin) continue;
419 if(xticks[i]>xMax) break;
420 //Attention erreur d'arrondi x->0 (on code 5.1698e-26 au lieu de 0)
421 double xx = (fabs(xticks[i]/xstep)<1.e-5) ? 0.: xticks[i];
422 sprintf(label,format.c_str(),xx/fac); Arrange_Label(label);
423 double largeur = g->CalcStringWidth(label);
424 g->DUC2GrC(largeur,0.,largpix,dum);
425 g->UC2GrC(xticks[i],y,xpixdeb,dum); xpixdeb -= largpix/2.;
426 //cout<<"xticks="<<xticks[i]<<" largpix="<<largpix
427 // <<" xpixdeb="<<xpixdeb<<" xpixfin="<<xpixfin<<endl;
428 if((aXdir && xpixdeb<xpixfin) || (!aXdir && xpixdeb>xpixfin)) {
429 g->DrawString(xticks[i],y,label,PI_HorizontalCenter|just);
430 xpixfin = xpixdeb + 1.1*largpix;
431 }
432 }
433
434 if(npuiss!=0) {
435 PIGrCoord asc,desc;
436 double h = g->GetFontHeight(asc,desc);
437 if((aYdir && (just&PI_VerticalBottom)) || (!aYdir && (just&PI_VerticalTop))) h=-h;
438 double xm = (aXdir)? xMin: xMax;
439 double ym = g->DeltaUCY(y,h);
440 sprintf(label,"%d",npuiss);
441 g->DrawCompString(xm,ym,"x 10",label,NULL,PI_HorizontalCenter|just);
442 }
443
444}
445
446/* --Methode-- */
447void PIAxes::DrawVLabels(PIGraphicUC* g, double x, vector<double>& yticks, unsigned long just)
448{
449 if(yticks.size()==0) return;
450
451 // Choix du bon format pour les labels des axes;
452 string format; double ystep;
453 int npuiss = Le_Bon_Format(yticks,format,ystep);
454 double fac=(npuiss!=0)? fac=pow(10.,(double)npuiss): 1.;
455
456 char label[64];
457 PIGrCoord asc,desc;
458 double dum,ypixdeb,ypixfin,hautpix,hauteur=g->GetFontHeight(asc,desc);
459 g->DUC2GrC(0.,hauteur,dum,hautpix);
460 g->UC2GrC(x,yMin-2.*(yMax-yMin),dum,ypixfin);
461 for(unsigned int i=0;i<yticks.size();i++) {
462 if(yticks[i]<yMin) continue;
463 if(yticks[i]>yMax) break;
464 double yy = (fabs(yticks[i]/ystep)<1.e-5) ? 0.: yticks[i];
465 sprintf(label,format.c_str(),yy/fac); Arrange_Label(label);
466 g->UC2GrC(x,yticks[i],dum,ypixdeb); ypixdeb -= hautpix/2.;
467 // -- Attention: ypix=0 est en haut de l'ecran
468 // (ypix croissants vers le bas de l'ecran)
469 // donc bien que yMin<yMax on a yMinPix>yMaxPix
470 //cout<<"yticks="<<yticks[i]<<" hautpix="<<hautpix
471 // <<" ypixdeb="<<ypixdeb<<" ypixfin="<<ypixfin<<endl;
472 if((aYdir && ypixdeb>ypixfin) || (!aYdir && ypixdeb<ypixfin)) {
473 g->DrawString(x,yticks[i],label,PI_VerticalCenter|just);
474 ypixfin = ypixdeb + 1.1*hautpix;
475 }
476 }
477
478 if(npuiss!=0) {
479 if(aYdir) hauteur = -hauteur;
480 double ym = (aYdir)? yMin: yMax; ym = g->DeltaUCY(ym,0.5*hauteur);
481 sprintf(label,"%d",npuiss);
482 g->DrawCompString(x,ym,"x 10",label,NULL,PI_VerticalBottom|just);
483 }
484
485}
486
487/* --Methode-- */
488void PIAxes::DrawGrid(PIGraphicUC* g)
489{
490 PILineAtt savlineatt = g->GetLineAtt();
491 g->SelLine(PI_ThinDottedLine);
492
493 if(xMajTicks.size()>0)
494 for(unsigned int i=0;i<xMajTicks.size();i++) {
495 if(xMajTicks[i]>xMax) break;
496 g->DrawLine(xMajTicks[i], yMin, xMajTicks[i], yMax);
497 }
498
499 if(yMajTicks.size()>0)
500 for(unsigned int i=0;i<yMajTicks.size();i++) {
501 if(yMajTicks[i]>yMax) break;
502 g->DrawLine(xMin, yMajTicks[i], xMax, yMajTicks[i]);
503 }
504
505 g->SelLine(savlineatt);
506}
507
508////////////////////////////////////////////////////////////////////////
509//////////////////// METHODES STATIQUES ////////////////////////////////
510////////////////////////////////////////////////////////////////////////
511/* --Methode-Static-- */
512void PIAxes::ReSizeMinMax(bool axelog,double& vmin,double& vmax,double garde)
513// Calcul du min et du max du display a partir des valeurs min et max a plotter
514{
515 if(garde<0. || garde>=1.) garde = 0.025;
516 // cout<<"ReSizeMinMax[log="<<axelog<<",garde="<<garde<<"] vmin="<<vmin<<" vmax="<<vmax<<endl;
517 // Cas d'une echelle lineaire
518 if(!axelog || vmax<=0.) {
519 double dv = garde*(vmax-vmin);
520 vmin -= dv;
521 vmax += dv;
522 }
523
524 // Cas d'une echelle log avec un range raisonnable
525 else if(vmin>0.) {
526 double dv = pow(vmax/vmin,garde);
527 vmin /= dv;
528 vmax *= dv;
529 }
530
531 // Cas d'une echelle log avec un range de-raisonnable
532 else if(vmin<=0.) {
533 if(vmin<0.) vmin += garde*vmin;
534 if(vmax==1.) vmax = 1.+garde;
535 if(vmax>1.) vmax = pow(vmax,1.+garde);
536 else vmax = pow(vmax,1.-garde);
537 }
538
539 // cout<<" vmin="<<vmin<<" vmax="<<vmax<<endl;
540}
541
542/* --Methode-Static-- */
543void PIAxes::BestTicks(double xmin,double xmax,int nticks
544 ,vector<double>& majticks,vector<double>& minticks)
545// *** Calcul de l'intervalle entre les ticks et de la valeur du premier tick
546// pour un axe lineaire
547{
548 if(nticks<=0) nticks = 1;
549
550 double d=xmax-xmin; if(d<1.e-100) d=1.e-100;
551 double ld = log10(d);
552 double fld = floor( ((ld<0.)? -ld: ld) );
553 double del,del0;
554 fld = (ld>=0.)? fld-2.: -(fld+2.);
555 del0 = del = pow(10.,fld);
556 // *** Intervalle entre les ticks
557 // xmin xmax d ld fld -->fld del0
558 // 1 1500 1499 3.17 3 1 10^1
559 // 1 9500 9499 3.98 3 1 10^1
560 // 1 1.005 0.005 -2.3 3 -5 10^-5
561 // 1 1.995 0.995 -0.0022 1 -3 10^-3
562 // - Et recherche de la valeur del={del0,2*del0,...,20*del0,...}
563 // telle que "nticks*del" soit le plus petit nombre ">=xmax-xmin"
564 double fac[9] = {2.,5.,10.,20.,50.,100.,200.,500.,1000.};
565 for(int k=0;k<9;k++) {
566 //cout<<"BestTicks: "<<k<<" del="<<del<<" d/del="<<d/del<<"<"<<nticks<<endl;
567 if(d/del < (double)nticks) break;
568 del=fac[k]*del0;
569 }
570 double steptick=del;
571 //*** Valeur du premier tick
572 majticks.resize(0);
573 double xfirsttick = floor(fabs(xmin)/steptick)*steptick;
574 if(xmin<0.) xfirsttick *= -1.;
575 if(xfirsttick<xmin) xfirsttick += steptick;
576 while(xfirsttick<=xmax+steptick/10.)
577 {majticks.push_back(xfirsttick); xfirsttick+= steptick;}
578 //*** Gestion des ticks mineurs
579 minticks.resize(0);
580 if(majticks.size()>1) {
581 double steptickmin = steptick/5.;
582 double xfirsttickmin = majticks[0];
583 while(xfirsttickmin<=xmax+steptickmin/10.)
584 {minticks.push_back(xfirsttickmin); xfirsttickmin+= steptickmin;}
585 }
586}
587/* --Methode-Static-- */
588void PIAxes::BestTicksLog(double xmin,double xmax,int nticks
589 ,vector<double>& majticks,vector<double>& minticks)
590// *** Calcul des ticks pour un axe logarithmique
591{
592 if(nticks<=0) nticks = 1;
593 //cout<<"BestTicksLog: xmin="<<xmin<<" xmax="<<xmax<<" nticks="<<nticks<<endl;
594
595 // Si xmax<=0, on garde BestTicks
596 if(xmax<=0. ) {
597 //cout<<"Choix de BestTicks car xmax="<<xmax<<endl;
598 BestTicks(xmin,xmax,nticks,majticks,minticks);
599 return;
600 }
601
602 int dmin, dmax=int(floor(log10(xmax)));
603 if(xmin>0.) {
604 // Dynamique trop faible, on garde BestTicks
605 if(xmax/xmin<5.) {
606 //cout<<"Choix de BestTicks car xmax/xmin="<<xmax/xmin<<" <5"<<endl;
607 BestTicks(xmin,xmax,nticks,majticks,minticks);
608 return;
609 }
610 dmin=int(floor(log10(xmin)));
611 } else {
612 if(dmax>3) dmin = dmax/3;
613 else dmin = dmax-1;
614 }
615 if(dmax==dmin) dmax++; else if(dmax<dmin) dmax=dmin+1;
616 int inc = (dmax-dmin+1)/nticks; if(inc<1) inc=1;
617 //cout<<" dmin="<<dmin<<" dmax="<<dmax<<" inc="<<inc<<endl;
618
619 majticks.resize(0);
620 {for(int i=dmin;i<=dmax;i+=inc) {
621 double x = pow(10.,(double)i);
622 if(x<xmin || x>xmax) continue;
623 majticks.push_back(x);
624 }}
625 //cout<<"majticks.size()="<<majticks.size()<<endl;
626
627 // Pas de puissance de 10 dans l'intervalle on garde BestTicks
628 if(majticks.size()==0) {
629 BestTicks(xmin,xmax,nticks,majticks,minticks);
630 return;
631 }
632
633 // Pas suffisamment de ticks majeurs
634 if((int)majticks.size()<=nticks/2) {
635 int nins = nticks/(majticks.size()+1);
636 if(nins<=0) nins=1;
637 //cout<<"nins="<<nins<<endl;
638 // Sequence judicieuse pour remplir les ticks manquants
639 // nins = 1 on insere 3
640 // 2 2 5
641 // 3 2 4 6
642 // 4 1.5 2 4 6
643 // >=5 on reste au cas precedent
644 double seqmaj[4][4] = {{3.,0,0,0},{2.,5.,0,0},{2.,4.,6.,0},{1.5,2.,4.,6.}};
645 if(nins>4) nins=4;
646 vector<double> tmp;
647 {for(unsigned int i=0;i<=majticks.size();i++) {
648 double xt;
649 if(i<majticks.size()) xt = majticks[i]/10.;
650 else xt = majticks[i-1];
651 for(int n=0;n<nins;n++) {
652 double xins = seqmaj[nins-1][n]*xt;
653 if(xins<xmin || xins>xmax) continue;
654 tmp.push_back(xins);
655 }
656 if(i<majticks.size()) tmp.push_back(majticks[i]);
657 }}
658 majticks = tmp;
659 }
660 //cout<<"...majticks.size()="<<majticks.size()<<endl;
661
662 // Les ticks mineurs
663 minticks.resize(0);
664 {for(unsigned int i=0;i<majticks.size()-1;i++) {
665 double dx = (majticks[i+1]-majticks[i])/10.;
666 minticks.push_back(majticks[i]);
667 for(int j=2;j<=8;j+=2) {
668 double x = majticks[i] + j*dx;
669 if(x<xmin || x>xmax) continue;
670 minticks.push_back(x);
671 }
672 }}
673 minticks.push_back(majticks[majticks.size()-1]);
674 //cout<<"...minticks.size()="<<minticks.size()<<endl;
675
676 // Si on a xmin<=0., on insere zero dans les ticks majeurs
677 if(xmin<=0.) {
678 vector<double> tmp = majticks;
679 majticks.resize(0); majticks.push_back(0.);
680 for(unsigned int i=0;i<tmp.size();i++) majticks.push_back(tmp[i]);
681 //cout<<"...xmin="<<xmin<<"<=0. add majticks[0]="<<majticks[0]<<endl;
682 }
683
684}
685
686/* --Methode-Static-- */
687int PIAxes::BonFormatAxes(double xmin,double xmax,double xstep
688 ,string& format,int typf,int add_digit)
689// *** Calcul format optimal pour ecrire les labels numeriques des axes:
690// ---- Input
691// . xmin,xmax : limites du plot sur l'axe considere.
692// . xstep : distance entre les ticks.
693// . add_digit : nombre de digits a ajouter au nombre de digits minimum.
694// . typf : type de format en sortie
695// 0 : format optimum %-nn.mme ou %-nn.mmf selon valeurs
696// 1 : format %-nn.mme
697// 2 : format %-nn.mmf pour imprimer x/10^npuiss
698// tel que x/10^npuiss soit entre [0,10]
699// 3 : format %-nn.mmf
700// ---- Output
701// . format : le format d'impression
702// ---- Return:
703// Si typ=0 ou 1 ou 3
704// "ndig" : nombre de digits necessaires pour distinguer
705// les valeurs xmin+k*dx (<=xmax)
706// Si typ=2
707// "npuiss" : tel que x/10^npuiss soit entre 0 et 10
708// Dans ce cas le format est celui qui imprime x/10^npuiss
709{
710 format = "%-5g"; // format par default
711 if(xmin>=xmax) {if(typf==2) return 0; else return -1;}
712
713 if(xstep<=0. || xstep>xmax-xmin) xstep = xmax-xmin;
714
715 double axmin=fabs(xmin), axmax=fabs(xmax);
716 if(axmin>axmax) dble_SWAP(axmin,axmax);
717
718 double l10amax = log10(axmax), l10xstep = log10(xstep);
719 int il10amax = int(floor(l10amax));
720
721 // choix du type de format
722 char ftype = 'e';
723 int npuiss = 0;
724 if(typf==2) {
725 npuiss = il10amax-1; // nombre entre [0,10]
726 //npuiss = il10amax; // nombre entre [0,1]
727 if(npuiss<-300 || npuiss>300) {
728 ftype='e'; npuiss=0;
729 } else {
730 // On recalcule les valeurs de decision pour axmax/10^npuiss, xstep/10^npuiss
731 l10amax -= (double)npuiss; l10xstep -= (double)npuiss;
732 il10amax = int(floor(l10amax));
733 ftype = 'f';
734 }
735 } else if(typf==1) {
736 ftype='e';
737 } else if(typf==3) {
738 ftype='f';
739 } else {
740 ftype='e';
741 // On evite d'ecrire +a.bbbe+ccc -> format %f
742 // Ex: 1.2345e+2 -> 123.45 / -1.2345e+2 -> -123.45
743 // 1.2345e-1 -> 0.12345 / -1.2345e-1 -> -0.12345
744 if((axmin>=1e-4 || axmin==0.) && axmax<1e4) ftype='f';
745 }
746
747 //printf("BonFormatAxes[npuiss=%d]: xmin=%-21.14e xmax=%-21.14e\n",npuiss,xmin,xmax);
748 //printf(" xstep=%-21.14e log10(xstep/10^%d)=%g\n",xstep,npuiss,l10xstep);
749 //printf(" axmax=%-21.14e log10(axmax/10^%d)=%g diff=%g\n"
750 // ,axmax,npuiss,l10amax,l10amax-l10xstep);
751
752 // Nombre de digits necessaires pour ecrire axmax et xstep
753 int ndig = il10amax - int(floor(l10xstep));
754 if(ndig<0) ndig *= -1; ndig += 1;
755 //printf("ndig=%d",ndig);
756
757 // Add more digits (or suppress digits)
758 ndig += add_digit; if(ndig<0) ndig=0;
759 //printf(" + %d ==> ndig=%d\n",add_digit,ndig);
760
761 // Calcul du bon format
762 char str[16];
763 if(ftype=='f') { // Calcul du format %-nn.mmf
764 int mm=-1, nn;
765 if(il10amax<0) { // +0.12345 +0.0012345 +0.0012345 ...
766 mm = ndig - il10amax - 1; nn = mm+3;
767 } else { // +1.2345 +12.345 +123.45 ...
768 mm = ndig - il10amax - 1; nn = ndig+2;
769 }
770 //printf("format %%f : mm=%d nn=%d\n",mm,nn);
771 if(mm<0.) mm=0; if(nn<mm+3) nn=mm+3;
772 sprintf(str,"%%-%d.%df",nn,mm);
773 } else if(ftype=='e') { // Calcul du format %-nn.mme
774 // +d.<--ddd-->e+123
775 // 1 2 34567 ==> nn=ndig+7 mm=ndig-1
776 sprintf(str,"%%-%d.%de",ndig+7,ndig-1);
777 }
778
779 format = str;
780 //printf("format=[%s]\n",format.c_str());
781
782 if(typf==2) return npuiss;
783 return ndig;
784}
785
786/* --Methode-- */
787int PIAxes::Le_Bon_Format(vector<double>& xticks,string& format,double& xstep)
788// Methode static de decision du bon format
789// Decide quel format est le mieux adapte pour ecrire les labels des axes
790// Decide si une puissance de 10 doit etre deportee en bout d'axe
791// - Input:
792// xticks : vecteur des ticks a ecrire (calcule par BestTicks)
793// - Output:
794// format : format a utiliser
795// xstep : step entre 2 graduations
796// - Return:
797// npuiss : si format choisit avec ecriture
798// avec label des puissances de 10 deporte
799// 0 : sinon
800{
801 format="%g"; xstep=1.;
802 if(xticks.size()<=1) return 0;
803
804 // On decide du format
805 xstep=xticks[1]-xticks[0];
806 int npuiss = BonFormatAxes(xticks[0],xticks[xticks.size()-1],xstep,format,2,1);
807 if(npuiss>=-2 && npuiss<=2) {
808 npuiss = 0;
809 BonFormatAxes(xticks[0],xticks[xticks.size()-1],xstep,format,3,1);
810 }
811
812 return npuiss;
813}
814
815void PIAxes::Arrange_Label(char *label)
816// --- Mise en forme optimale du label numerique
817// Enleve les blancs, les zeros, le point et les e00
818// inutiles a la fin d'un label
819{
820 size_t lenl=strlen(label);
821 if(lenl==0) return;
822
823 // --- On enleve les blancs et plus au debut du label
824 if(label[0]==' ' || label[0]=='+') {
825 char *str=new char[lenl+2];
826 strcpy(str,label);
827 unsigned i=0;
828 for(i=0;i<lenl;i++) if(str[i]!=' ' && str[i]!='+') break;
829 strcpy(label,&str[i]);
830 delete [] str;
831 lenl=strlen(label);
832 if(lenl==0) return;
833 }
834
835 // --- On enleve les blancs a la fin du label
836 if(label[lenl-1]==' ') {
837 for(int i=lenl-1;i>=0;i--) {
838 if(label[i]!=' ') break;
839 label[i]='\0';
840 }
841 lenl=strlen(label);
842 }
843
844 // --- On enleve les e... E... non-significatifs
845 // ex: a.be-zzz a.be+zzz a.bezzz avec zzz=0,00,000,...
846 // Attention on n'enleve pas si: a.be+10
847 // Attention on ne fait rien si: e+10
848 char* e=index(label,'e');
849 if(e==NULL) e=index(label,'E');
850 if(e) {
851 for(int i=lenl-1;i>=0;i--) {
852 if(isdigit(label[i]) && label[i]!='0') break;
853 if(label[i]=='e' || label[i]=='E')
854 {label[i]='\0'; lenl=strlen(label); break;}
855 }
856 }
857
858 // --- On enleve les zeros non-significatifs a la fin du label
859 // On enleve des zeros ou le point si: ab. ab.czzz avec zzz=0,00,000,...
860 // Attention on n'enleve pas de zeros si: abzzz
861 // Attention a ne pas enlever des zeros si on a ab.ccce+a0
862 // Attention on traite 0eaaa -> 0
863 if(index(label,'.')==NULL) return; // Recherche d'un point
864 string stre;
865 if(e) {if(e==label) return; stre=e; *e='\0'; lenl=strlen(label);}
866 {for(int i=lenl-1;i>=0;i--) {
867 if(label[i]=='0') label[i]='\0';
868 else if(label[i]=='.') {
869 if(i>0) label[i]='\0';
870 else {
871 // Attention: ".e+10" -> "1e+10" MAIS "." -> "0"
872 if(e) strcpy(label,"1"); else strcpy(label,"0");
873 }
874 break;
875 }
876 else break; // Ni un point ni un zero
877 }}
878 if(e) {
879 if(strlen(label)==1) if(label[0]=='0') return;
880 strcat(label,stre.c_str());
881 }
882
883}
Note: See TracBrowser for help on using the repository browser.