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

Last change on this file since 4074 was 4074, checked in by ansari, 13 years ago

petit changement ds trace label axes polaires et MAJ numero de version PI, Reza 10/05/2012

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