// Module PI : Peida Interactive PIAxes // Methodes de trace des axes // R. Ansari - 2002 // LAL (Orsay) / IN2P3-CNRS DAPNIA/SPP (Saclay) / CEA #include "machdefs.h" #include #include #include "piaxes.h" inline void dble_SWAP(double a, double b) {double tmp=a; a=b; b=tmp;} /* --Methode-- */ PIAxes::PIAxes() { } /* --Methode-- */ PIAxes::~PIAxes() { } /* --Methode-- */ void PIAxes::DrawXYAxes(PIGraphicUC* g, PIGraphicAtt& gratt, unsigned int flags, bool afsz) { PIGrCoord xmin, xmax, ymin, ymax; g->GetGrSpace(xmin, xmax, ymin, ymax); DrawXYAxes(g, gratt, flags, afsz, (double)xmin, (double)xmax, (double)ymin, (double)ymax); } /* --Methode-- */ void PIAxes::DrawXYAxes(PIGraphicUC* g, PIGraphicAtt& gratt, unsigned int flags, bool afsz, double xmin, double xmax, double ymin, double ymax) { Setup(g, xmin, xmax, ymin, ymax); // g->NoClip(); if (gratt.GetLineAtt() == PI_NotDefLineAtt) g->SelLine(PI_ThinLine); else g->SelLine(gratt.GetLineAtt()); if (gratt.GetColor() == PI_NotDefColor) g->SelForeground(PI_Black); else g->SelForeground(gratt.GetColor()); if(afsz) { double fsz = xMajTickLen*3.5; g->SelFontSz(fsz); } if (flags & kStdAxes) { // Les axes g->DrawLine(xMin, (yMin+yMax)/2., xMax, (yMin+yMax)/2.); g->DrawLine((xMin+xMax)/2., yMin, (xMin+xMax)/2., yMax); // La grille en pointilles if (flags & kGridOn) DrawGrid(g); // Les ticks majeurs if (flags & kMajTicks) { DrawHTicks(g, (yMin+yMax)/2., xMajTickLen, xMajTickLen, xMajTicks); DrawVTicks(g, (xMin+xMax)/2., yMajTickLen, yMajTickLen, yMajTicks); } // Les ticks mineurs if (flags & kMinTicks) { DrawHTicks(g, (yMin+yMax)/2., xMinTickLen, xMinTickLen, xMinTicks); DrawVTicks(g, (xMin+xMax)/2., yMinTickLen, yMinTickLen, yMinTicks); } // Les labels if (flags & kLabels) { if (!aYdir) DrawHLabels(g, (yMin+yMax)/2.-xMajTickLen*2, xMajTicks, PI_VerticalTop); else DrawHLabels(g, (yMin+yMax)/2.+xMajTickLen*2, xMajTicks, PI_VerticalTop); if (!aXdir) DrawVLabels(g, (xMin+xMax)/2.-yMajTickLen*2, yMajTicks, PI_HorizontalRight); else DrawVLabels(g, (xMin+xMax)/2.+yMajTickLen*2, yMajTicks, PI_HorizontalRight); } } if (flags & kBoxAxes) { // La boite g->DrawLine(xMin, yMin, xMax, yMin); g->DrawLine(xMax, yMin, xMax, yMax); g->DrawLine(xMax, yMax, xMin, yMax); g->DrawLine(xMin, yMax, xMin, yMin); // Longueur des ticks double extXMajTickLen = flags&kExtTicks ? xMajTickLen : 0; double intXMajTickLen = flags&kIntTicks ? xMajTickLen : 0; double extXMinTickLen = flags&kExtTicks ? xMinTickLen : 0; double intXMinTickLen = flags&kIntTicks ? xMinTickLen : 0; double extYMajTickLen = flags&kExtTicks ? yMajTickLen : 0; double intYMajTickLen = flags&kIntTicks ? yMajTickLen : 0; double extYMinTickLen = flags&kExtTicks ? yMinTickLen : 0; double intYMinTickLen = flags&kIntTicks ? yMinTickLen : 0; // La grille en pointilles if (flags & kGridOn) DrawGrid(g); // Les ticks majeurs if (flags & kMajTicks) { DrawHTicks(g, yMin, intXMajTickLen, extXMajTickLen, xMajTicks); DrawHTicks(g, yMax, extXMajTickLen, intXMajTickLen, xMajTicks); DrawVTicks(g, xMin, extYMajTickLen, intYMajTickLen, yMajTicks); DrawVTicks(g, xMax, intYMajTickLen, extYMajTickLen, yMajTicks); } // Les ticks mineurs if (flags & kMinTicks) { DrawHTicks(g, yMin, intXMinTickLen, extXMinTickLen, xMinTicks); DrawHTicks(g, yMax, extXMinTickLen, intXMinTickLen, xMinTicks); DrawVTicks(g, xMin, extYMinTickLen, intYMinTickLen, yMinTicks); DrawVTicks(g, xMax, intYMinTickLen, extYMinTickLen, yMinTicks); } // Les labels if (flags & kLabels) { if (!aYdir) { DrawHLabels(g, g->DeltaUCY(yMin, -xMajTickLen*2), xMajTicks, PI_VerticalTop); } else { DrawHLabels(g, g->DeltaUCY(yMax, xMajTickLen*2), xMajTicks, PI_VerticalTop); } if (!aXdir) { DrawVLabels(g, g->DeltaUCX(xMin, -yMajTickLen*2), yMajTicks, PI_HorizontalRight); } else { DrawVLabels(g, g->DeltaUCX(xMax, yMajTickLen*2), yMajTicks, PI_HorizontalRight); } } } g->Clip(); } /* --Methode-- */ void PIAxes::Setup(PIGraphicUC* g, double xmin, double xmax, double ymin, double ymax) { xMin = xmin; xMax = xmax; yMin = ymin; yMax = ymax; aXdir = g->isAxeXDirRtoL(); aYdir = g->isAxeYDirUpDown(); aXlog = g->isLogScaleX(); aYlog = g->isLogScaleY(); int ntick_x = (aXlog) ? 6 : 10; BestTicks(xMin,xMax,ntick_x,xMajTicks,xMinTicks); int ntick_y = (aYlog) ? 6 : 12; BestTicks(yMin,yMax,ntick_y,yMajTicks,yMinTicks); yMajTickLen = (xMax-xMin)/100; yMinTickLen = (xMax-xMin)/250; xMajTickLen = (yMax-yMin)/100; xMinTickLen = (yMax-yMin)/250; } /* --Methode-- */ void PIAxes::DrawHTicks(PIGraphicUC* g, double y, double tickUp, double tickDown, vector& xticks) { if(xticks.size()<=0) return; for(unsigned int i=0;ixMax) break; g->DrawLine(xticks[i],g->DeltaUCY(y,-tickDown),xticks[i],g->DeltaUCY(y,tickUp)); } } /* --Methode-- */ void PIAxes::DrawVTicks(PIGraphicUC* g, double x, double tickLeft, double tickRight, vector& yticks) { if(yticks.size()<=0) return; for(unsigned int i=0;iyMax) break; g->DrawLine(g->DeltaUCX(x,-tickLeft),yticks[i],g->DeltaUCX(x,tickRight),yticks[i]); } } /* --Methode-- */ void PIAxes::DrawHLabels(PIGraphicUC* g, double y, vector& xticks, unsigned long just) { if(xticks.size()<=1) return; // Choix du bon format pour les labels des axes; char label[64]; string format; double fac=1.; bool p10=false; double xstep=xticks[1]-xticks[0]; int npuiss = BonFormatAxes(xticks[0],xMax,xstep,format,2,1); if(npuiss<-2 || npuiss>3) {p10 = true; fac=pow(10.,(double)npuiss);} else BonFormatAxes(xticks[0],xMax,xstep,format,0,1); double xOffset = 0; double xlastlabelfin = xticks[0] - 2.*(xMax-xticks[0]); for(unsigned int i=0;ixMax) break; //Attention erreur d'arrondi x->0 (on code 5.1698e-26 au lieu de 0) double xx = (fabs(xticks[i]/xstep)<1.e-5) ? 0.: xticks[i]; sprintf(label,format.c_str(),xx/fac); Arrange_Label(label); double largeur = g->CalcStringWidth(label); if(aXdir) xOffset = largeur/2; else xOffset=-largeur/2; if(xticks[i]+xOffset > xlastlabelfin) { g->DrawString(xticks[i],y,label,PI_HorizontalCenter|just); xlastlabelfin = xticks[i] + xOffset + 1.1*largeur; } } if(p10) { PIGrCoord asc,desc; double h = g->GetFontHeight(asc,desc); if((aYdir && (just&PI_VerticalBottom)) || (!aYdir && (just&PI_VerticalTop)) ) h = -h; double xm = (aXdir)? xMin: xMax; double ym = g->DeltaUCY(y,1.5*h); sprintf(label,"%d",npuiss); g->DrawCompString(xm,ym,"x 10",label,NULL,PI_HorizontalCenter|just); } } /* --Methode-- */ void PIAxes::DrawVLabels(PIGraphicUC* g, double x, vector& yticks, unsigned long just) { if(yticks.size()<=1) return; // Choix du bon format pour les labels des axes; char label[64]; string format; double fac=1.; bool p10=false; double ystep=yticks[1]-yticks[0]; int npuiss = BonFormatAxes(yticks[0],yMax,ystep,format,2,1); if(npuiss<-2 || npuiss>3) {p10 = true; fac=pow(10.,(double)npuiss);} else BonFormatAxes(yticks[0],yMax,ystep,format,0,1); for(unsigned int i=0;iyMax) break; double yy = (fabs(yticks[i]/ystep)<1.e-5) ? 0.: yticks[i]; sprintf(label,format.c_str(),yy/fac); Arrange_Label(label); g->DrawString(x,yticks[i],label,PI_VerticalCenter|just); } if(p10) { PIGrCoord asc,desc; double h = g->GetFontHeight(asc,desc); if(aYdir) h = -h; double ym = (aYdir)? yMin: yMax; ym = g->DeltaUCY(ym,h); sprintf(label,"%d",npuiss); g->DrawCompString(x,ym,"x 10",label,NULL,PI_VerticalBottom|just); } } /* --Methode-- */ void PIAxes::DrawGrid(PIGraphicUC* g) { PILineAtt savlineatt = g->GetLineAtt(); g->SelLine(PI_ThinDottedLine); if(xMajTicks.size()>0) for(unsigned int i=0;ixMax) break; g->DrawLine(xMajTicks[i], yMin, xMajTicks[i], yMax); } if(yMajTicks.size()>0) for(unsigned int i=0;iyMax) break; g->DrawLine(xMin, yMajTicks[i], xMax, yMajTicks[i]); } g->SelLine(savlineatt); } /////////////////////////////////////////////////////////////////////////// /* --Methode-Static-- */ void PIAxes::BestTicks(double xmin,double xmax,int nticks ,vector& majticks,vector& minticks) // *** Calcul de l'intervalle entre les ticks et de la valeur du premier tick { double d=xmax-xmin; if(d<1.e-100) d=1.e-100; //if (d<1.e-39) d=1.e-39; double ld = log10(d); double fld = floor( ((ld<0.)? -ld: ld) ); double del,del0; majticks.resize(0); minticks.resize(0); if(ld>=0.) {fld-=1.; del0=del=pow(10.,fld);} else {fld+=2.; del0=del=pow(10.,-fld);} // *** Intervalle entre les ticks // xmin xmax d ld fld -->fld del0 // 1 1500 1499 3.17 3 2 10^2 // 1 9500 9499 3.98 3 2 10^2 // 1 1.005 0.005 -2.3 2 4 10^-4 // 1 1.995 0.995 -0.0022 0 2 10^-2 // - Et recherche de la valeur del={del0,2*del0,...,20*del0} // telle que "nticks*del" soit le plus petit nombre ">=d" // Par exemple, si nticks=10: // 1-/ pour le 2sd cas ou d=9499 et del0=100 : // del = 100 200 500 1000 2000 // nticks*del = 1000 2000 5000 10000 20000 // d/del = 94.9 47.4 18.9 | 9.499 4.749 ==> majt = 1000 // 2-/ pour le 3ieme cas ou d=5e-3 et del0=1e-4 : // del = 1e-4 2e-4 5e-4 1e-3 2e-3 // nticks*del = 1e-3 2e-3 5e-3 1e-2 2e-2 // d/del = 50 25 | 10 5 2.5 ==> majt = 5e-4 int k=0; double fac[4] = {2.,5.,10.,20.}; while(d/del>(double)nticks && k<4 ) {del=fac[k]*del0; k++;} double steptick=del; //*** Valeur du premier tick double xfirsttick = floor(xmin/steptick); if(xmin<0.) xfirsttick+=1.; xfirsttick *= steptick; if(xfirsttick=xmax) {if(typf==2) return 0; else return -1;} if(xstep<=0. || xstep>xmax-xmin) xstep = xmax-xmin; double axmin=fabs(xmin), axmax=fabs(xmax); if(axmin>axmax) dble_SWAP(axmin,axmax); double l10amax = log10(axmax), l10xstep = log10(xstep); int il10amax = int(floor(l10amax)); // choix du type de format char ftype = 'e'; int npuiss = 0; if(typf==2) { npuiss = il10amax; if(npuiss<-300 || npuiss>300) { ftype='e'; npuiss=0; } else { // On recalcule les valeurs de decision pour axmax/10^npuiss, xstep/10^npuiss l10amax -= (double)npuiss; l10xstep -= (double)npuiss; il10amax = int(floor(l10amax)); ftype = 'f'; } } else if(typf==1) { ftype='e'; } else { ftype='e'; // On evite d'ecrire +a.bbbe+ccc -> format %f // Ex: 1.2345e+2 -> 123.45 / -1.2345e+2 -> -123.45 // 1.2345e-1 -> 0.12345 / -1.2345e-1 -> -0.12345 if((axmin>=1e-4 || axmin==0.) && axmax<1e4) ftype='f'; } //printf("BonFormatAxes[npuiss=%d]: xmin=%-21.14e xmax=%-21.14e\n",npuiss,xmin,xmax); //printf(" xstep=%-21.14e log10(xstep/10^%d)=%g\n",xstep,npuiss,l10xstep); //printf(" axmax=%-21.14e log10(axmax/10^%d)=%g diff=%g\n" // ,axmax,npuiss,l10amax,l10amax-l10xstep); // Nombre de digits necessaires pour ecrire axmax et xstep int ndig = il10amax - int(floor(l10xstep)); if(ndig<0) ndig *= -1; ndig += 1; //printf("ndig=%d",ndig); // Add more digits (or suppress digits) ndig += add_digit; if(ndig<0) ndig=0; //printf(" + %d ==> ndig=%d\n",add_digit,ndig); // Calcul du bon format char str[16]; if(ftype=='f') { // Calcul du format %-nn.mmf int mm=-1, nn; if(il10amax<0) { // +0.12345 +0.0012345 +0.0012345 ... mm = ndig - il10amax - 1; nn = mm+3; } else { // +1.2345 +12.345 +123.45 ... mm = ndig - il10amax - 1; nn = ndig+2; } //printf("format %%f : mm=%d nn=%d\n",mm,nn); if(mm<0.) mm=0; if(nne+123 // 1 2 34567 ==> nn=ndig+7 mm=ndig-1 sprintf(str,"%%-%d.%de",ndig+7,ndig-1); } format = str; //printf("format=[%s]\n",format.c_str()); if(typf==2) return npuiss; return ndig; } void PIAxes::Arrange_Label(char *label) // Enleve les blancs et les zeros inutiles a la fin d'un label { size_t lenl=strlen(label); if(lenl==0) return; // --- On enleve les blancs et plus au debut du label if(label[0]==' ' || label[0]=='+') { char *str=new char[lenl+2]; strcpy(str,label); unsigned i=0; for(i=0;i=0;i--) { if(label[i]!=' ') break; label[i]='\0'; } lenl=strlen(label); } // --- On enleve les e... E... non-significatifs // ex: a.be-zzz a.be+zzz a.bezzz avec zzz=0,00,000,... // Attention on n'enleve pas si: a.be+10 // Attention on ne fait rien si: e+10 char* e=index(label,'e'); if(e==NULL) e=index(label,'E'); if(e) { for(unsigned int i=lenl-1;i>=0;i--) { if(isdigit(label[i]) && label[i]!='0') break; if(label[i]=='e' || label[i]=='E') {label[i]='\0'; lenl=strlen(label); break;} } } // --- On enleve les zeros non-significatifs a la fin du label // On enleve des zeros ou le point si: ab. ab.czzz avec zzz=0,00,000,... // Attention on n'enleve pas de zeros si: abzzz // Attention a ne pas enlever des zeros si on a ab.ccce+a0 // Attention on traite 0eaaa -> 0 if(index(label,'.')==NULL) return; // Recherche d'un point string stre; if(e) {if(e==label) return; stre=e; *e='\0'; lenl=strlen(label);} for(unsigned int i=lenl-1;i>=0;i--) { if(label[i]=='0') label[i]='\0'; else if(label[i]=='.') { if(i>0) label[i]='\0'; else { // Attention: ".e+10" -> "1e+10" MAIS "." -> "0" if(e) strcpy(label,"1"); else strcpy(label,"0"); } break; } else break; // Ni un point ni un zero } if(e) { if(strlen(label)==1) if(label[0]=='0') return; strcat(label,stre.c_str()); } }