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

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

Correction probleme limites de trace ds ucckprot.h et MAJ Makefile, cmv+reza 16/04/2012

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