Main Page   Class Hierarchy   Alphabetical List   Compound List   File List   Compound Members   File Members  

xyax.cpp

Go to the documentation of this file.
00001 /*****************************************************************************/
00002 /* Módulo: xyax.cpp                                                          */
00003 /* Autores: Carlos Henrique Levy e Jaudênia Cavalcante                       */
00004 /* Data: 26 fev 96                                                           */
00005 /* Comentário:                                                               */
00006 /*    Implementação de métodos da classe abstrata que define as característi */
00007 /* cas de um eixo. Um eixo representa a escala de um tipo de coordenada. A   */
00008 /* sua representação visual é composta de uma linha reta podendo ter ou não  */
00009 /* terminador (seta), textos próximo a reta indicando a escala e por último  */
00010 /* um título para o eixo.                                                    */
00011 /*****************************************************************************/
00012 
00013 #include <stdlib.h>
00014 #include <math.h>
00015 #include <stdio.h>
00016 
00017 #include "xyax.h"
00018 
00019 const char* xy_id_xyax_cpp="$Id: xyax.cpp,v 1.22 1999/12/09 21:47:46 rborges Exp $";                                                            
00020 const double XYAxis::_arrow_size = 0.03;
00021                                                                 
00022 XYAxis::XYAxis (double mn,
00023                       double mx,
00024                 XYCoordinate x,
00025                 XYCoordinate y,
00026                       long color,
00027                       double size,
00028                       double rot,
00029                       double step,
00030                       XYScaleDecorator* decorator,
00031                       XYText* title,
00032                       xybool arrow,
00033                       xybool visible)
00034                       : XYObject(x, y, visible),
00035                         _mn(mn), _mx(mx), _color(color), _size(size), _rot(rot),
00036                         _step(step), _referenceTick(mn), _decor(decorator),
00037                         _title(title), _arrow(arrow), _leftTick(xytrue)
00038 {
00039 }
00040 
00041 XYAxis::XYAxis (double mn,
00042                       double mx,
00043                 XYCoordinate x,
00044                 XYCoordinate y,
00045                       long color,
00046                       double size,
00047                       double rot,
00048                       xybool arrow,
00049                       xybool visible)
00050                       : XYObject(x, y, visible),
00051                         _mn(mn), _mx(mx), _color(color), _size(size), _rot(rot),
00052                         _step(0), _referenceTick(mn), _decor(NULL),
00053                         _title(NULL), _arrow(arrow), _leftTick(xytrue)
00054 {
00055 }
00056 
00057 XYAxis::XYAxis (double mn,
00058                       double mx,
00059                 XYCoordinate x,
00060                 XYCoordinate y,
00061                       long color,
00062                       double size,
00063                       double rot,
00064                       double step,
00065                       xybool arrow,
00066                       xybool visible)
00067                       : XYObject(x, y, visible),
00068                         _mn(mn), _mx(mx), _color(color), _size(size), _rot(rot),
00069                        _step(step), _referenceTick(mn), _decor(NULL),
00070                        _title(NULL), _arrow(arrow), _leftTick(xytrue)
00071 {
00072 }
00073 
00074 void XYAxis::min (double min)
00075 {
00076    _mn = min;
00077 }
00078 
00079 double XYAxis::min (void) const
00080 {
00081    return _mn;
00082 }
00083 
00084 void XYAxis::max (double max)
00085 {
00086    _mx = max;
00087 }
00088 
00089 double XYAxis::max (void) const
00090 {
00091    return _mx;
00092 }
00093 
00094 void XYAxis::color (long c)
00095 {
00096    _color = c;
00097 }
00098 
00099 long XYAxis::color (void) const
00100 {
00101    return _color;
00102 }
00103 
00104 void XYAxis::size (double sz)
00105 {
00106    if ((0.0 <= sz) && (sz <= 1.0))
00107       _size = sz;
00108 }
00109 
00110 double XYAxis::size (void) const
00111 {
00112    return _size;
00113 }
00114 
00115 void XYAxis::rotation (double rot)
00116 {
00117    _rot = rot;
00118 }
00119 
00120 double XYAxis::rotation (void) const
00121 {
00122    return _rot;
00123 }
00124 
00125 void XYAxis::step (double s)
00126 {
00127    _step = s;
00128 }
00129 
00130 double XYAxis::step (void) const
00131 {
00132    return _step;
00133 }
00134 
00135 void XYAxis::referenceTick (double f)
00136 {
00137    _referenceTick = f;
00138 }
00139 
00140 double XYAxis::referenceTick (void) const
00141 {
00142    return _referenceTick;
00143 }
00144 
00145 void XYAxis::leftTick (xybool left)
00146 {
00147    _leftTick = left;
00148 }
00149 
00150 xybool XYAxis::leftTick (void) const
00151 {
00152    return _leftTick;
00153 }
00154 
00155 double XYAxis::first (void) const
00156 {
00157    double first = _referenceTick;
00158 
00159    if (_referenceTick < _mn)
00160      for ( ;first < _mn; first += _step)
00161         ;
00162    else
00163      //for ( ;first - _step > _mn; first -= _step)
00164      for ( ;mtLessEqual(_mn, first - _step); first -= _step)
00165         ;
00166 
00167    return first;
00168 }
00169 
00170 void XYAxis::scaleDecorator(XYScaleDecorator* decor)
00171 {
00172    _decor = decor;
00173 }
00174 
00175 XYScaleDecorator* XYAxis::scaleDecorator(void) const
00176 {
00177    return _decor;
00178 }
00179                                 
00180 void XYAxis::arrow (xybool a)
00181 {
00182    _arrow = a;
00183 }
00184 
00185 xybool XYAxis::arrow (void) const
00186 {
00187    return _arrow;
00188 }
00189 
00190 void XYAxis::title (XYText* t)
00191 {
00192    _title = t;
00193 }
00194 
00195 XYText* XYAxis::title (void) const
00196 {
00197    return _title;
00198 }
00199 
00200 double XYAxis::transform (double e) const
00201 {
00202    return e;
00203 }
00204 
00205 double XYAxis::defineMinPoint(double, int, int) const
00206 {
00207    return _mn;
00208 }
00209 
00210 double XYAxis::defineMaxPoint(double, int, int) const
00211 {
00212    return _mx;
00213 }
00214 
00215 double XYAxis::valueInPoint(int, int) const
00216 {
00217    return (_mx - _mn) / 2;
00218 }
00219 
00220 double XYAxis::valueInPoint(double, double) const
00221 {
00222    return (_mx - _mn) / 2;
00223 }
00224 
00225 xybool XYAxis::pick (int px, int py)
00226 {
00227    if (visible() == xyfalse)    // invisível!!!
00228       return xyfalse;
00229 
00230    // limites da menor caixa que contém um eixo
00231    int x1, y1, x2, y2;
00232    boundingBox (x1, y1, x2, y2);
00233 
00234    return mtPointInRect (px, py, x1, y1, x2, y2);
00235 }
00236 
00237 xybool XYAxis::fence (int x2, int y2, int x3, int y3)
00238 {
00239    if (visible() == xyfalse)           // invisível!!!
00240       return xyfalse;
00241 
00242    // limites da menor caixa que contém um eixo
00243    int x0, y0, x1, y1;
00244    boundingBox (x0, y0, x1, y1);
00245 
00246    return mtInclude (x0, y0, x1, y1, x2, y2, x3, y3);
00247 }
00248 
00249 void XYAxis::firstTick (double& tx1, double& ty1, double& tx2, double& ty2)
00250                                     const
00251 {
00252    double tick_size = 0.01;
00253 
00254    // ângulo de rotação em radianos
00255    double rot_rad = _rot * XY_PI / 180.0;
00256 
00257    // primeira posição normalizada no eixo em relação ao canvas
00258    double f = (first() - _mn) * _size / (_mx - _mn);
00259 
00260    // consulta posição de desenho do eixo
00261    double x0, y0;
00262    position (&x0, &y0);
00263 
00264    // (x1, y1) ponto inferior esquerdo no eixo
00265    double x1 = x0 + f * cos (rot_rad);
00266    double y1 = y0 + f * sin (rot_rad);
00267 
00268    // (x2, y2) ponto superior direito no eixo
00269    double x2 = x1 + _size * cos (rot_rad);
00270    double y2 = y1 + _size * sin (rot_rad);
00271 
00272    // controle de ponto flutuante
00273    if (mtEqual(x1, x2))
00274       x2 = x1;
00275    if (mtEqual(y1, y2))
00276       y2 = y1;
00277 
00278    // (tx1, ty1) coordenadas sobre o eixo
00279    tx1 = x1;
00280    ty1 = y1;
00281 
00282    if (_leftTick)
00283       mtRotate(tick_size, 0.0, rot_rad + XY_PI / 2.0, &tx2, &ty2);
00284    else
00285       mtRotate(tick_size, 0.0, rot_rad - XY_PI / 2.0, &tx2, &ty2);
00286 
00287    tx2 += x1;
00288    ty2 += y1;
00289 
00290    // controle de ponto flutuante
00291    if (mtEqual(tx1, tx2))
00292       tx2 = tx1;
00293    if (mtEqual(ty1, ty2))
00294       ty2 = ty1;
00295 }
00296 
00297 void XYAxis::drawArrow(double x0, double y0, double x1, double y1) const
00298 {
00299    // intervalo normalizado em relação as direções x e y
00300    double ca = (x1 - x0) / mtDistance(x0, y0, x1, y1);
00301    double sa = (y1 - y0) / mtDistance(x0, y0, x1, y1);
00302 
00303    // tamanho da seta em relação às coordenadas da janela
00304    double as = mtDistance(x0, y0, x1, y1) * _arrow_size;
00305 
00306    //desenha a seta
00307    wdBegin (CD_FILL);
00308    wdVertex(x1 + 0.3333 * as * sa, y1 - 0.3333 * as * ca);
00309    wdVertex(x1 + as * ca, y1 + as * sa);
00310    wdVertex(x1 - 0.3333 * as * sa, y1 + 0.3333 * as * ca);
00311    wdEnd();
00312 }
00313 
00314 void XYAxis::boxArrow(double x0, double y0, double x1, double y1, double& xmin,
00315                                   double& ymin, double& xmax, double& ymax) const
00316 {
00317    // intervalo normalizado em relação as direções x e y
00318    double ca = (x1 - x0) / mtDistance(x0, y0, x1, y1);
00319    double sa = (y1 - y0) / mtDistance(x0, y0, x1, y1);
00320 
00321    // tamanho da seta em relação às coordenadas da janela
00322    double as = mtDistance(x0, y0, x1, y1) * _arrow_size;
00323 
00324    // boundinBox da seta
00325    xmin = xmax = x1 + 0.3333 * as * sa;
00326 
00327    if (x1 + as * ca < xmin)
00328       xmin = x1 + as * ca;
00329    else if (x1 + as * ca > xmax)
00330       xmax = x1 + as * ca;
00331 
00332    if ((x1 - 0.3333 * as * sa) < xmin)
00333       xmin = x1 - 0.3333 * as * sa;
00334    else if ((x1 - 0.3333 * as * sa) > xmax)
00335       xmax = x1 - 0.3333 * as * sa;
00336 
00337    ymin = ymax = y1 + 0.3333 * as * ca;
00338 
00339    if (y1 + as * sa < ymin)
00340       ymin = y1 + as * sa;
00341    else if (y1 + as * sa > ymax)
00342       ymax = y1 + as * sa;
00343 
00344    if ((y1 - 0.3333 * as * ca) < ymin)
00345       ymin = y1 - 0.3333 * as * ca;
00346    else if ((y1 - 0.3333 * as * ca) > ymax)
00347       ymax = y1 - 0.3333 * as * ca;
00348 }
00349 
00350 void XYAxis::adjustSize (void)
00351 {
00352    if ((_xmin == _xmax) && (_ymin == _ymax))
00353       return;
00354 
00355    // passo normalizado na grade em relação ao canvas
00356    double step_n = _step * _size / (_mx - _mn);
00357 
00358    // ângulo de rotação em radianos
00359    double rot_rad = _rot * XY_PI / 180.0;
00360 
00361    // intervalo de deslocamento em relação as direções x e y
00362    double dx;
00363    double dy;
00364    mtRotate (step_n, 0, rot_rad, &dx, &dy);
00365 
00366    // calcula o passo, em pixels
00367    int pdx, pdy;
00368    wdWorld2Canvas (dx, dy, &pdx, &pdy);
00369 
00370    // volta o passo para normalizado para recalcular o novo tamanho
00371    wdCanvas2World (pdx, pdy, &dx, &dy);
00372 
00373    step_n = mtDistance (dx, 0.0, 0.0, dy);
00374 
00375    _size = (_mx - _mn) * step_n / _step;
00376 
00377    int pdx1;
00378    wdWorld2Canvas (_step * _size / (_mx - _mn), 0, &pdx1, 0);
00379 
00380    // fprintf (logfile, "\nXYAxis::adjustSize pdx = %d %d", pdx, pdx1);
00381 }
00382 
00383 void XYAxis::calcMinMax(double *min, double *max, double *step) const
00384 {
00385    #define OCUP_MIN   0.8 // taxa de ocupação no eixo
00386    #define MAX_DIGIT  8   // dígitos representados num inteiro
00387    #define MIN_MARCAS 4   // número mínimo de ticks
00388    #define MAX_MARCAS 12  // número máximo de ticks
00389 
00390    double y, expo;
00391    int expoente, passo, i;
00392    int imax, imin, resid, rmin, zero, zmin, exces, emin;
00393 
00394    if (*max == *min)
00395       if (*max == 0)
00396       {
00397                *max = (double)  1.0;
00398                *min = (double) -1.0;
00399       }
00400       else
00401       {
00402                *max += (double) (0.1 * fabs(*max));
00403                *min -= (double) (0.1 * fabs(*min));
00404       }
00405 
00406    if (*max + *min >= 0.0)
00407       y = *max;
00408    else
00409       y = - *min;
00410 
00411    expoente = (int) floor(log10(y));
00412    expo = (double) pow(10.0, expoente);
00413 
00414    imax = 0;
00415 
00416    if (*max >= 0.0)
00417       while (imax * expo < *max) imax++;
00418    else
00419       while ((imax - 1) * expo >= *max) imax--;
00420 
00421    imin = 0;
00422 
00423    if (*min > 0.0)
00424       while ((imin + 1) * expo <= *min) imin++;
00425    else
00426       while (imin * expo > *min) imin--;
00427 
00428    i = 1;
00429 
00430    while (((*max - *min) < OCUP_MIN * (imax - imin) * expo) && (i < MAX_DIGIT))
00431    {
00432       i++;
00433       expoente--;
00434       expo = (double) pow(10.0, expoente);
00435 
00436       imax = 10 * imax;
00437       imin = 10 * imin;
00438 
00439       while ((imax - 1) * expo >= *max)
00440                imax--;
00441       while ((imin + 1) * expo <= *min)
00442                imin++;
00443    }
00444 
00445    *step = (double) (imax - imin + 1);
00446 
00447    if (*step > MAX_MARCAS)
00448    {
00449       *step = (double) 0;
00450       zmin = 30000;
00451       rmin = 30000;
00452       emin = 30000;
00453 
00454       for (i = MIN_MARCAS; i <= MAX_MARCAS; i++)
00455       {
00456                passo = (int) ceil((double) (imax - imin) / (i - 1));
00457 
00458                if (imax >= 0 && imin <= 0)
00459               zero = (int) (imin + passo * ceil(- (double) imin / passo));
00460                else
00461                   zero = 0;
00462 
00463                resid = (i - 1) * passo - (imax - imin);
00464 
00465                if (resid >= zero)
00466                   exces = 0;
00467                else
00468                   exces = zero = resid;
00469 
00470                if ((emin != 0 && exces == 0) || ( resid <= rmin && ((emin != 0) ||
00471                    (emin == 0 && exces == 0 ))))
00472                {
00473                   *step = (double) i;
00474                   emin = exces;
00475                   rmin = resid;
00476                   zmin = zero;
00477                }
00478       }
00479 
00480       if (emin == 0)
00481       {
00482                imin -= zmin;
00483                imax += rmin - zmin;
00484       }
00485       else
00486          imin -= rmin;
00487    }
00488    else
00489       while (*step < MIN_MARCAS)
00490          *step += *step - 1;
00491 
00492    *max = imax * expo;
00493    *min = imin * expo;
00494    *step = (*max - *min) / (*step - 1);
00495 }
00496 

XY
Tecgraf / PUC-Rio - Computer Graphics Technology Group