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

Last change on this file since 2088 was 2088, checked in by cmv, 23 years ago

PIAxes: nouvelle gestion axes, add simpleaxesgrid finesimpleaxesgrid finesimpleaxes cmv 11/7/2002

File size: 15.8 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>
[2080]8#include <math.h>
[2088]9#include "piaxes.h"
[2080]10
11inline void dble_SWAP(double a, double b) {double tmp=a; a=b; b=tmp;}
12
13/* --Methode-- */
14PIAxes::PIAxes()
15{
16}
17
18/* --Methode-- */
19PIAxes::~PIAxes()
20{
21}
22
23/* --Methode-- */
24void PIAxes::DrawXYAxes(PIGraphicUC* g, PIGraphicAtt& gratt,
25 unsigned int flags, bool afsz)
26{
27 PIGrCoord xmin, xmax, ymin, ymax;
28 g->GetGrSpace(xmin, xmax, ymin, ymax);
29 DrawXYAxes(g, gratt, flags, afsz, (double)xmin, (double)xmax,
30 (double)ymin, (double)ymax);
31}
32
33/* --Methode-- */
34void PIAxes::DrawXYAxes(PIGraphicUC* g, PIGraphicAtt& gratt,
35 unsigned int flags, bool afsz,
36 double xmin, double xmax, double ymin, double ymax)
37{
38 Setup(g, xmin, xmax, ymin, ymax);
39 // g->NoClip();
40
41 if (gratt.GetLineAtt() == PI_NotDefLineAtt) g->SelLine(PI_ThinLine);
42 else g->SelLine(gratt.GetLineAtt());
43 if (gratt.GetColor() == PI_NotDefColor) g->SelForeground(PI_Black);
44 else g->SelForeground(gratt.GetColor());
45
46 if(afsz) {
47 double fsz = xMajTickLen*3.5;
48 g->SelFontSz(fsz);
49 }
50
51 if (flags & kStdAxes) {
52
53 // Les axes
54
55 g->DrawLine(xMin, (yMin+yMax)/2., xMax, (yMin+yMax)/2.);
56 g->DrawLine((xMin+xMax)/2., yMin, (xMin+xMax)/2., yMax);
57
58 // La grille en pointilles
59
60 if (flags & kGridOn) DrawGrid(g);
61
62 // Les ticks majeurs
63
64 if (flags & kMajTicks) {
[2088]65 DrawHTicks(g, (yMin+yMax)/2., xMajTickLen, xMajTickLen, xMajTicks);
66 DrawVTicks(g, (xMin+xMax)/2., yMajTickLen, yMajTickLen, yMajTicks);
[2080]67 }
68
69 // Les ticks mineurs
70
71 if (flags & kMinTicks) {
[2088]72 DrawHTicks(g, (yMin+yMax)/2., xMinTickLen, xMinTickLen, xMinTicks);
73 DrawVTicks(g, (xMin+xMax)/2., yMinTickLen, yMinTickLen, yMinTicks);
[2080]74 }
75
76 // Les labels
77
78 if (flags & kLabels) {
79 if (!aYdir)
[2088]80 DrawHLabels(g, (yMin+yMax)/2.-xMajTickLen*2, xMajTicks, PI_VerticalTop);
[2080]81 else
[2088]82 DrawHLabels(g, (yMin+yMax)/2.+xMajTickLen*2, xMajTicks, PI_VerticalTop);
[2080]83 if (!aXdir)
[2088]84 DrawVLabels(g, (xMin+xMax)/2.-yMajTickLen*2, yMajTicks, PI_HorizontalRight);
[2080]85 else
[2088]86 DrawVLabels(g, (xMin+xMax)/2.+yMajTickLen*2, yMajTicks, PI_HorizontalRight);
[2080]87 }
88
89 }
90
91 if (flags & kBoxAxes) {
92
93 // La boite
94
95 g->DrawLine(xMin, yMin, xMax, yMin);
96 g->DrawLine(xMax, yMin, xMax, yMax);
97 g->DrawLine(xMax, yMax, xMin, yMax);
98 g->DrawLine(xMin, yMax, xMin, yMin);
99
100 // Longueur des ticks
101
102 double extXMajTickLen = flags&kExtTicks ? xMajTickLen : 0;
103 double intXMajTickLen = flags&kIntTicks ? xMajTickLen : 0;
104 double extXMinTickLen = flags&kExtTicks ? xMinTickLen : 0;
105 double intXMinTickLen = flags&kIntTicks ? xMinTickLen : 0;
106 double extYMajTickLen = flags&kExtTicks ? yMajTickLen : 0;
107 double intYMajTickLen = flags&kIntTicks ? yMajTickLen : 0;
108 double extYMinTickLen = flags&kExtTicks ? yMinTickLen : 0;
109 double intYMinTickLen = flags&kIntTicks ? yMinTickLen : 0;
110
111 // La grille en pointilles
112
113 if (flags & kGridOn) DrawGrid(g);
114
115 // Les ticks majeurs
116
117 if (flags & kMajTicks) {
[2088]118 DrawHTicks(g, yMin, intXMajTickLen, extXMajTickLen, xMajTicks);
119 DrawHTicks(g, yMax, extXMajTickLen, intXMajTickLen, xMajTicks);
120 DrawVTicks(g, xMin, extYMajTickLen, intYMajTickLen, yMajTicks);
121 DrawVTicks(g, xMax, intYMajTickLen, extYMajTickLen, yMajTicks);
[2080]122 }
123
124 // Les ticks mineurs
125
126 if (flags & kMinTicks) {
[2088]127 DrawHTicks(g, yMin, intXMinTickLen, extXMinTickLen, xMinTicks);
128 DrawHTicks(g, yMax, extXMinTickLen, intXMinTickLen, xMinTicks);
129 DrawVTicks(g, xMin, extYMinTickLen, intYMinTickLen, yMinTicks);
130 DrawVTicks(g, xMax, intYMinTickLen, extYMinTickLen, yMinTicks);
[2080]131 }
132
133
134 // Les labels
135
136 if (flags & kLabels) {
137 if (!aYdir) {
[2088]138 DrawHLabels(g, g->DeltaUCY(yMin, -xMajTickLen*2), xMajTicks, PI_VerticalTop);
[2080]139 }
140 else {
[2088]141 DrawHLabels(g, g->DeltaUCY(yMax, xMajTickLen*2), xMajTicks, PI_VerticalTop);
[2080]142 }
143 if (!aXdir) {
[2088]144 DrawVLabels(g, g->DeltaUCX(xMin, -yMajTickLen*2), yMajTicks, PI_HorizontalRight);
[2080]145 }
146 else {
[2088]147 DrawVLabels(g, g->DeltaUCX(xMax, yMajTickLen*2), yMajTicks, PI_HorizontalRight);
[2080]148 }
149 }
150 }
151 g->Clip();
152
153}
154
155/* --Methode-- */
156void PIAxes::Setup(PIGraphicUC* g, double xmin, double xmax,
157 double ymin, double ymax)
158{
159
160 xMin = xmin; xMax = xmax;
161 yMin = ymin; yMax = ymax;
162
163 aXdir = g->isAxeXDirRtoL();
164 aYdir = g->isAxeYDirUpDown();
165 aXlog = g->isLogScaleX();
166 aYlog = g->isLogScaleY();
167
168 int ntick_x = (aXlog) ? 6 : 10;
[2088]169 BestTicks(xMin,xMax,ntick_x,xMajTicks,xMinTicks);
[2080]170
171 int ntick_y = (aYlog) ? 6 : 12;
[2088]172 BestTicks(yMin,yMax,ntick_y,yMajTicks,yMinTicks);
[2080]173
174 yMajTickLen = (xMax-xMin)/100;
175 yMinTickLen = (xMax-xMin)/250;
176 xMajTickLen = (yMax-yMin)/100;
177 xMinTickLen = (yMax-yMin)/250;
178}
179
180
181/* --Methode-- */
182void PIAxes::DrawHTicks(PIGraphicUC* g, double y, double tickUp,
[2088]183 double tickDown, vector<double>& xticks)
[2080]184{
[2088]185 if(xticks.size()<=0) return;
186 for(unsigned int i=0;i<xticks.size();i++) {
187 if(xticks[i]>xMax) break;
188 g->DrawLine(xticks[i],g->DeltaUCY(y,-tickDown),xticks[i],g->DeltaUCY(y,tickUp));
189 }
[2080]190}
191
192/* --Methode-- */
193void PIAxes::DrawVTicks(PIGraphicUC* g, double x, double tickLeft,
[2088]194 double tickRight, vector<double>& yticks)
[2080]195{
[2088]196 if(yticks.size()<=0) return;
197 for(unsigned int i=0;i<yticks.size();i++) {
198 if(yticks[i]>yMax) break;
199 g->DrawLine(g->DeltaUCX(x,-tickLeft),yticks[i],g->DeltaUCX(x,tickRight),yticks[i]);
200 }
[2080]201}
202
203/* --Methode-- */
[2088]204void PIAxes::DrawHLabels(PIGraphicUC* g, double y, vector<double>& xticks, unsigned long just)
[2080]205{
206
[2088]207 if(xticks.size()<=1) return;
[2080]208 // Choix du bon format pour les labels des axes;
209 char label[64]; string format; double fac=1.; bool p10=false;
[2088]210 double xstep=xticks[1]-xticks[0];
211 int npuiss = BonFormatAxes(xticks[0],xMax,xstep,format,2,1);
[2080]212 if(npuiss<-2 || npuiss>3) {p10 = true; fac=pow(10.,(double)npuiss);}
[2088]213 else BonFormatAxes(xticks[0],xMax,xstep,format,0,1);
[2080]214
215 double xOffset = 0;
[2088]216 double xlastlabelfin = xticks[0] - 2.*(xMax-xticks[0]);
217 for(unsigned int i=0;i<xticks.size();i++) {
218 if(xticks[i]>xMax) break;
[2080]219 //Attention erreur d'arrondi x->0 (on code 5.1698e-26 au lieu de 0)
[2088]220 double xx = (fabs(xticks[i]/xstep)<1.e-5) ? 0.: xticks[i];
[2080]221 sprintf(label,format.c_str(),xx/fac);
[2088]222 Arrange_Label(label);
[2080]223 double largeur = g->CalcStringWidth(label);
224 if(aXdir) xOffset = largeur/2; else xOffset=-largeur/2;
[2088]225 if(xticks[i]+xOffset > xlastlabelfin) {
226 g->DrawString(xticks[i],y,label,PI_HorizontalCenter|just);
227 xlastlabelfin = xticks[i] + xOffset + 1.1*largeur;
[2080]228 }
229 }
230
231 if(p10) {
232 PIGrCoord asc,desc;
233 double h = g->GetFontHeight(asc,desc);
234 if((aYdir && (just&PI_VerticalBottom)) || (!aYdir && (just&PI_VerticalTop)) ) h = -h;
235 double xm = (aXdir)? xMin: xMax;
236 double ym = g->DeltaUCY(y,1.5*h);
237 sprintf(label,"%d",npuiss);
238 g->DrawCompString(xm,ym,"x 10",label,NULL,PI_HorizontalCenter|just);
239 }
240
241}
242
243/* --Methode-- */
[2088]244void PIAxes::DrawVLabels(PIGraphicUC* g, double x, vector<double>& yticks, unsigned long just)
[2080]245{
246
[2088]247 if(yticks.size()<=1) return;
[2080]248 // Choix du bon format pour les labels des axes;
249 char label[64]; string format; double fac=1.; bool p10=false;
[2088]250 double ystep=yticks[1]-yticks[0];
251 int npuiss = BonFormatAxes(yticks[0],yMax,ystep,format,2,1);
[2080]252 if(npuiss<-2 || npuiss>3) {p10 = true; fac=pow(10.,(double)npuiss);}
[2088]253 else BonFormatAxes(yticks[0],yMax,ystep,format,0,1);
[2080]254
[2088]255 for(unsigned int i=0;i<yticks.size();i++) {
256 if(yticks[i]>yMax) break;
257 double yy = (fabs(yticks[i]/ystep)<1.e-5) ? 0.: yticks[i];
[2080]258 sprintf(label,format.c_str(),yy/fac);
[2088]259 Arrange_Label(label);
260 g->DrawString(x,yticks[i],label,PI_VerticalCenter|just);
[2080]261 }
262
263 if(p10) {
264 PIGrCoord asc,desc;
265 double h = g->GetFontHeight(asc,desc);
266 if(aYdir) h = -h;
267 double ym = (aYdir)? yMin: yMax; ym = g->DeltaUCY(ym,h);
268 sprintf(label,"%d",npuiss);
269 g->DrawCompString(x,ym,"x 10",label,NULL,PI_VerticalBottom|just);
270 }
271
272}
273
274/* --Methode-- */
275void PIAxes::DrawGrid(PIGraphicUC* g)
276{
277 PILineAtt savlineatt = g->GetLineAtt();
278 g->SelLine(PI_ThinDottedLine);
279
[2088]280 if(xMajTicks.size()>0)
281 for(unsigned int i=0;i<xMajTicks.size();i++) {
282 if(xMajTicks[i]>xMax) break;
283 g->DrawLine(xMajTicks[i], yMin, xMajTicks[i], yMax);
284 }
[2080]285
[2088]286 if(yMajTicks.size()>0)
287 for(unsigned int i=0;i<yMajTicks.size();i++) {
288 if(yMajTicks[i]>yMax) break;
289 g->DrawLine(xMin, yMajTicks[i], xMax, yMajTicks[i]);
290 }
[2080]291
292 g->SelLine(savlineatt);
293}
294
295
296///////////////////////////////////////////////////////////////////////////
297/* --Methode-Static-- */
298void PIAxes::BestTicks(double xmin,double xmax,int nticks
[2088]299 ,vector<double>& majticks,vector<double>& minticks)
[2080]300// *** Calcul de l'intervalle entre les ticks et de la valeur du premier tick
301{
[2088]302 double d=xmax-xmin; if(d<1.e-100) d=1.e-100; //if (d<1.e-39) d=1.e-39;
303 double ld = log10(d);
304 double fld = floor( ((ld<0.)? -ld: ld) );
305 double del,del0;
306 majticks.resize(0); minticks.resize(0);
307 if(ld>=0.) {fld-=1.; del0=del=pow(10.,fld);}
308 else {fld+=2.; del0=del=pow(10.,-fld);}
309 // *** Intervalle entre les ticks
310 // xmin xmax d ld fld -->fld del0
311 // 1 1500 1499 3.17 3 2 10^2
312 // 1 9500 9499 3.98 3 2 10^2
313 // 1 1.005 0.005 -2.3 2 4 10^-4
314 // 1 1.995 0.995 -0.0022 0 2 10^-2
315 // - Et recherche de la valeur del={del0,2*del0,...,20*del0}
316 // telle que "nticks*del" soit le plus petit nombre ">=d"
317 // Par exemple, si nticks=10:
318 // 1-/ pour le 2sd cas ou d=9499 et del0=100 :
319 // del = 100 200 500 1000 2000
320 // nticks*del = 1000 2000 5000 10000 20000
321 // d/del = 94.9 47.4 18.9 | 9.499 4.749 ==> majt = 1000
322 // 2-/ pour le 3ieme cas ou d=5e-3 et del0=1e-4 :
323 // del = 1e-4 2e-4 5e-4 1e-3 2e-3
324 // nticks*del = 1e-3 2e-3 5e-3 1e-2 2e-2
325 // d/del = 50 25 | 10 5 2.5 ==> majt = 5e-4
326 int k=0;
327 double fac[4] = {2.,5.,10.,20.};
328 while(d/del>(double)nticks && k<4 ) {del=fac[k]*del0; k++;}
329 double steptick=del;
330 //*** Valeur du premier tick
331 double xfirsttick = floor(xmin/steptick); if(xmin<0.) xfirsttick+=1.;
332 xfirsttick *= steptick;
333 if(xfirsttick<xmin) xfirsttick += steptick;
334 majticks.push_back(xfirsttick);
335 while(xfirsttick<=xmax)
336 {xfirsttick+= steptick; majticks.push_back(xfirsttick);}
337 //*** Gestion des ticks mineurs
338 double steptickmin = steptick/5.;
339 double xfirsttickmin = floor(xmin/steptickmin) * steptickmin;
340 if(xfirsttickmin<xmin) xfirsttickmin += steptickmin;
341 minticks.push_back(xfirsttickmin);
342 while(xfirsttickmin<=xmax)
343 {xfirsttickmin+= steptickmin; minticks.push_back(xfirsttickmin);}
[2080]344}
345
346/* --Methode-Static-- */
347int PIAxes::BonFormatAxes(double xmin,double xmax,double xstep
348 ,string& format,int typf,int add_digit)
349// *** Calcul format optimal pour ecrire les labels numeriques des axes:
350// ---- Input
351// . xmin,xmax : limites du plot sur l'axe considere.
352// . xstep : distance entre les ticks.
353// . add_digit : nombre de digits a ajouter au nombre de digits minimum.
354// . typf : type de format en sortie
355// 0 : format optimum %-nn.mme ou %-nn.mmf selon valeurs
356// 1 : format %-nn.mme
357// 2 : format %-nn.mmf pour imprimer x/10^npuiss
358// tel que x/10^npuiss soit entre 0 et 10
359// ---- Output
360// . format : le format d'impression
361// ---- Return:
362// Si typ=0 ou 1
363// "ndig" : nombre de digits necessaires pour distinguer
364// les valeurs xmin+k*dx (<=xmax)
365// Si typ=2
366// "npuiss" : tel que x/10^npuiss soit entre 0 et 10
367// Dans ce cas le format est celui qui imprime x/10^npuiss
368{
369 format = "%-5g"; // format par default
370 if(xmin>=xmax) {if(typf==2) return 0; else return -1;}
371
372 if(xstep<=0. || xstep>xmax-xmin) xstep = xmax-xmin;
373
374 double axmin=fabs(xmin), axmax=fabs(xmax);
375 if(axmin>axmax) dble_SWAP(axmin,axmax);
376
377 double l10amax = log10(axmax), l10xstep = log10(xstep);
378 int il10amax = int(floor(l10amax));
379
380 // choix du type de format
381 char ftype = 'e';
382 int npuiss = 0;
383 if(typf==2) {
384 npuiss = il10amax;
385 if(npuiss<-300 || npuiss>300) {
386 ftype='e'; npuiss=0;
387 } else {
388 // On recalcule les valeurs de decision pour axmax/10^npuiss, xstep/10^npuiss
389 l10amax -= (double)npuiss; l10xstep -= (double)npuiss;
390 il10amax = int(floor(l10amax));
391 ftype = 'f';
392 }
393 } else if(typf==1) {
394 ftype='e';
395 } else {
396 ftype='e';
397 // On evite d'ecrire +a.bbbe+ccc -> format %f
398 // Ex: 1.2345e+2 -> 123.45 / -1.2345e+2 -> -123.45
399 // 1.2345e-1 -> 0.12345 / -1.2345e-1 -> -0.12345
400 if((axmin>=1e-4 || axmin==0.) && axmax<1e4) ftype='f';
401 }
402
403 //printf("BonFormatAxes[npuiss=%d]: xmin=%-21.14e xmax=%-21.14e\n",npuiss,xmin,xmax);
404 //printf(" xstep=%-21.14e log10(xstep/10^%d)=%g\n",xstep,npuiss,l10xstep);
405 //printf(" axmax=%-21.14e log10(axmax/10^%d)=%g diff=%g\n"
406 // ,axmax,npuiss,l10amax,l10amax-l10xstep);
407
408 // Nombre de digits necessaires pour ecrire axmax et xstep
409 int ndig = il10amax - int(floor(l10xstep));
410 if(ndig<0) ndig *= -1; ndig += 1;
411 //printf("ndig=%d",ndig);
412
413 // Add more digits (or suppress digits)
414 ndig += add_digit; if(ndig<0) ndig=0;
415 //printf(" + %d ==> ndig=%d\n",add_digit,ndig);
416
417 // Calcul du bon format
418 char str[16];
419 if(ftype=='f') { // Calcul du format %-nn.mmf
420 int mm=-1, nn;
421 if(il10amax<0) { // +0.12345 +0.0012345 +0.0012345 ...
422 mm = ndig - il10amax - 1; nn = mm+3;
423 } else { // +1.2345 +12.345 +123.45 ...
424 mm = ndig - il10amax - 1; nn = ndig+2;
425 }
426 //printf("format %%f : mm=%d nn=%d\n",mm,nn);
427 if(mm<0.) mm=0; if(nn<mm+3) nn=mm+3;
428 sprintf(str,"%%-%d.%df",nn,mm);
429 } else if(ftype=='e') { // Calcul du format %-nn.mme
430 // +d.<--ddd-->e+123
431 // 1 2 34567 ==> nn=ndig+7 mm=ndig-1
432 sprintf(str,"%%-%d.%de",ndig+7,ndig-1);
433 }
434
435 format = str;
436 //printf("format=[%s]\n",format.c_str());
437
438 if(typf==2) return npuiss;
439 return ndig;
440}
441
[2088]442void PIAxes::Arrange_Label(char *label)
443// Enleve les blancs et les zeros inutiles a la fin d'un label
444{
445 size_t lenl=strlen(label);
446 if(lenl==0) return;
447
448 // --- On enleve les blancs et plus au debut du label
449 if(label[0]==' ' || label[0]=='+') {
450 char *str=new char[lenl+2];
451 strcpy(str,label);
452 unsigned i=0;
453 for(i=0;i<lenl;i++) if(str[i]!=' ' && str[i]!='+') break;
454 strcpy(label,&str[i]);
455 delete [] str;
456 lenl=strlen(label);
457 if(lenl==0) return;
458 }
459
460 // --- On enleve les blancs a la fin du label
461 if(label[lenl-1]==' ') {
462 for(unsigned int i=lenl-1;i>=0;i--) {
463 if(label[i]!=' ') break;
464 label[i]='\0';
465 }
466 lenl=strlen(label);
467 }
468
469 // --- On enleve les e... E... non-significatifs
470 // ex: a.be-zzz a.be+zzz a.bezzz avec zzz=0,00,000,...
471 // Attention on n'enleve pas si: a.be+10
472 // Attention on ne fait rien si: e+10
473 char* e=index(label,'e');
474 if(e==NULL) e=index(label,'E');
475 if(e) {
476 for(unsigned int i=lenl-1;i>=0;i--) {
477 if(isdigit(label[i]) && label[i]!='0') break;
478 if(label[i]=='e' || label[i]=='E')
479 {label[i]='\0'; lenl=strlen(label); break;}
480 }
481 }
482
483 // --- On enleve les zeros non-significatifs a la fin du label
484 // On enleve des zeros ou le point si: ab. ab.czzz avec zzz=0,00,000,...
485 // Attention on n'enleve pas de zeros si: abzzz
486 // Attention a ne pas enlever des zeros si on a ab.ccce+a0
487 // Attention on traite 0eaaa -> 0
488 if(index(label,'.')==NULL) return; // Recherche d'un point
489 string stre;
490 if(e) {if(e==label) return; stre=e; *e='\0'; lenl=strlen(label);}
491 for(unsigned int i=lenl-1;i>=0;i--) {
492 if(label[i]=='0') label[i]='\0';
493 else if(label[i]=='.') {
494 if(i>0) label[i]='\0';
495 else {
496 // Attention: ".e+10" -> "1e+10" MAIS "." -> "0"
497 if(e) strcpy(label,"1"); else strcpy(label,"0");
498 }
499 break;
500 }
501 else break; // Ni un point ni un zero
502 }
503 if(e) {
504 if(strlen(label)==1) if(label[0]=='0') return;
505 strcat(label,stre.c_str());
506 }
507
508}
Note: See TracBrowser for help on using the repository browser.