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

sxy_graph.cpp

Go to the documentation of this file.
00001 // =======================================================================
00002 
00003 char *graph_cpp = "$Id: sxy_graph.cpp,v 1.8 2003/04/25 20:21:43 clinio Exp $";
00004 
00005 // =======================================================================
00006 
00007 #include <float.h>
00008 #include <stdlib.h>
00009 
00010 extern "C" {
00011 #include <iup.h>
00012 #include <cd.h>
00013 #include <cdiup.h>
00014 #include <cdps.h>
00015 #ifdef WIN32
00016 #include <cdprint.h>
00017 #include <cdclipbd.h>
00018 #endif
00019 }
00020 
00021 #include "sxy_graph.h"
00022 #include "sxy_task.h"
00023 #include "sxy_chart.h"
00024 #include "sxy_axis.h"
00025 #include "sxy_utils.h"
00026 
00027 // =======================================================================
00028 
00029 #define GRAPH_ATTR_NAME "GRAPH_POINTER"
00030 #define MAX_CHARTS  10
00031 #define MAX_TASKS   64
00032 
00033 // =======================================================================
00034 
00035 // .......................................................................
00036 
00039 SXYGraph::SXYGraph(Ihandle* iupcnv) : iup_canvas(iupcnv) {
00040 
00041   /* instrumentação de validação do canvas IUP */
00042   assert(iupcnv);
00043   IupMap(IupGetDialog(iupcnv));
00044 
00045   /* inicialização dos vetores */
00046   charts_vector = new SXYVector<SXYChart*>(MAX_CHARTS, NULL);
00047   tasks_vector = new SXYVector<SXYTask*>(MAX_TASKS, NULL);
00048 
00049   /* criação do canvas CD utilizando o driver IUP (com instarumentação) */
00050   cd_canvas = cdCreateCanvas(CD_IUP, iup_canvas);
00051   assert(cd_canvas);
00052 
00053   /* override das callbacks no IUP/Lua para métodos estáticos
00054    * da classe que fazem o repasse para métidos do objeto. */
00055   IupSetAttribute(iup_canvas, IUP_ACTION, "iupActionCallback");
00056   IupSetAttribute(iup_canvas, IUP_BUTTON_CB, "iupButtonCallback");
00057   IupSetAttribute(iup_canvas, IUP_MOTION_CB, "iupMotionCallback");
00058   IupSetAttribute(iup_canvas, IUP_RESIZE_CB, "iupResizeCallback");
00059   IupSetAttribute(iup_canvas, IUP_ENTERWINDOW_CB , "iupEnterCallback");
00060   IupSetAttribute(iup_canvas, IUP_LEAVEWINDOW_CB , "iupLeaveCallback");
00061 
00062   IupSetFunction("iupActionCallback", (Icallback)SXYGraph::iupActionCallback);
00063   IupSetFunction("iupButtonCallback", (Icallback)SXYGraph::iupButtonCallback);
00064   IupSetFunction("iupMotionCallback", (Icallback)SXYGraph::iupMotionCallback);
00065   IupSetFunction("iupResizeCallback", (Icallback)SXYGraph::iupResizeCallback);
00066   IupSetFunction("iupEnterCallback", (Icallback)SXYGraph::iupEnterCallback);
00067   IupSetFunction("iupLeaveCallback", (Icallback)SXYGraph::iupLeaveCallback);
00068 
00069   /* armazenamento do this como atributo do canvas IUP. Este atributo
00070    * será consultado para o repasse para o método do objeto 
00071    * (callbacks) */
00072   IupSetAttribute(iup_canvas, GRAPH_ATTR_NAME, (char*)this);
00073 }
00074 
00075 // .......................................................................
00076 
00078 SXYGraph::~SXYGraph() {
00079   /* liberação dos vetores */
00080   if (charts_vector) delete charts_vector;
00081   charts_vector = NULL;
00082 
00083   if (tasks_vector) delete tasks_vector;
00084   tasks_vector = NULL;
00085 
00086    /* finalização do canvas CD */
00087   cdKillCanvas(cd_canvas);
00088   cd_canvas = NULL;
00089 }
00090 
00091 // .......................................................................
00092 
00095 cdCanvas* SXYGraph::getCdCanvas(void) {
00096    return cd_canvas;
00097 }
00098 
00099 // .......................................................................
00100 
00103 Ihandle* SXYGraph::getIupCanvas(void) {
00104    return iup_canvas;
00105 }
00106 
00107 // .......................................................................
00108 
00109 int SXYGraph::getDeviceSizeMM(double& w, double& h) {
00110   double ww, hh;
00111   cdCanvas* cd = getCdCanvas();
00112   assert(cd);
00113   if (cdActivate(cd) == CD_ERROR) return 0;
00114   cdGetCanvasSize( NULL, NULL, &ww, &hh );
00115   w = ww; h = hh;
00116   return 1;
00117 }
00118 
00119 // .......................................................................
00120 
00121 void SXYGraph::fitAllAxis(SXYAxisOrientation orientation) {
00122   int ncharts = getNumCharts();
00123   double min = FLT_MAX, max = -FLT_MAX;
00124   int i;
00125 
00126   for (i = 0; i < ncharts; i++) {
00127     SXYChart* cht = getChart(i);
00128     if (cht) {
00129       int nxaxes = cht->getNumAxes(orientation);
00130       for (int j = 0; j < nxaxes; j++) 
00131       {
00132         SXYAxis* ax = cht->getAxis(orientation, j);
00133         double tmin, tmax;
00134         ax->getScales(tmin, tmax);
00135         if (tmin < min) min = tmin;
00136         if (tmax > max) max = tmax;
00137       }
00138     }
00139   }
00140 
00141   SXYUtil::calcZoomOut(min, max);
00142 
00143   for (i = 0; i < ncharts; i++) {
00144     SXYChart* cht = getChart(i);
00145     if (cht) cht->setAllAxis(orientation, min, max);
00146   }
00147 }
00148 
00149 // .......................................................................
00150 
00151 void SXYGraph::fitScales(SXYGraphFitOption opt) {
00152   /* Após o switch, faz-se um loop de fit em todos os charts XY.
00153    * Os eixos dos charts devem pelo suportar todas as curvas 
00154    * no fit. */
00155   switch(opt) {
00156     case ALL_X: {
00157       int ncharts = getNumCharts();
00158       for (int i = 0; i < ncharts; i++) {
00159          SXYChart* cht = getChart(i);
00160          if (cht) cht->fitScale(HORIZONTAL_AXIS);
00161       }
00162       fitAllAxis(HORIZONTAL_AXIS);
00163       break;
00164     }
00165     case ALL_Y: {
00166       int ncharts = getNumCharts();
00167       for (int i = 0; i < ncharts; i++) {
00168          SXYChart* cht = getChart(i);
00169          if (cht) cht->fitScale(VERTICAL_AXIS);
00170       }
00171       fitAllAxis(VERTICAL_AXIS);
00172       break;
00173     }
00174     case INDIVIDUAL_X: {
00175       int ncharts = getNumCharts();
00176       for (int i = 0; i < ncharts; i++) {
00177          SXYChart* cht = getChart(i);
00178          if (cht) cht->fitScale(HORIZONTAL_AXIS);
00179       }
00180       break;
00181     }
00182     case INDIVIDUAL_Y: {
00183       int ncharts = getNumCharts();
00184       for (int i = 0; i < ncharts; i++) {
00185          SXYChart* cht = getChart(i);
00186          if (cht) cht->fitScale(VERTICAL_AXIS);
00187       }
00188       break;
00189     }
00190   }
00191 }
00192 
00193 // .......................................................................
00194 
00195 void SXYGraph::setZoom(double xratio, double yratio) {
00196   /* loop de zoom sobre todos os charts XY */
00197   int ncharts = getNumCharts();
00198   for (int i = 0; i < ncharts; i++) {
00199      SXYChart* cht = getChart(i);
00200      if (cht) cht->setZoom(xratio, yratio);
00201   }
00202 }
00203 
00204 // .......................................................................
00205 
00206 void SXYGraph::drawChartsAt(cdCanvas* cnv, SXYGraphDoubleBufferMode mode) {
00207   /* segurança e instrumentação */
00208   assert(cnv != NULL);
00209 
00210   /* teste para ativação do canvas CD */
00211   if (cdActivate(cnv) == CD_ERROR) {
00212      IupMessage( "Erro interno", "Falha de desenho do gráfico!" );
00213      return;
00214   }
00215 
00216   /* loop de redesenho de todos os charts XY */
00217   int ncharts = getNumCharts();
00218   for (int i = 0; i < ncharts; i++) {
00219      SXYChart* cht = getChart(i);
00220      if (cht) cht->repaintChart(cnv, mode);
00221   }
00222 
00223   /* ativação do canvas CD que se refere ao display */
00224   activateDisplayCanvas();
00225 }
00226 
00227 // .......................................................................
00228 
00229 void SXYGraph::redrawGraph(void) {
00230   assert(cd_canvas);
00231   drawChartsAt(cd_canvas, WITH_DOUBLE_BUFFER);
00232   cdFlush();
00233 }
00234 
00235 // .......................................................................
00236 
00237 void SXYGraph::copyGraph(int width, int height) {
00238 #ifdef WIN32
00239   cdCanvas* clipboard_canvas = NULL;
00240   static char buffer[64];
00241   sprintf(buffer, "%dx%d", width, height);
00242   clipboard_canvas = cdCreateCanvas(CD_CLIPBOARD, buffer);
00243   if (clipboard_canvas == NULL) {
00244      fprintf( stderr, "No clipboard_canvas created for copyGraph()\n");
00245      return; 
00246   }
00247   drawChartsAt(clipboard_canvas, WITHOUT_DOUBLE_BUFFER);
00248   cdKillCanvas(clipboard_canvas);
00249 #endif
00250   redrawGraph();
00251 }
00252 
00253 // .......................................................................
00254 
00255 void SXYGraph::printGraph(int ask, char* ps_cmd) {
00256   cdCanvas* printer_canvas = NULL;
00257 #ifdef WIN32
00258   ps_cmd = NULL;
00259   if ( ask ) printer_canvas = cdCreateCanvas( CD_PRINTER, "SXY -d" );
00260   else       printer_canvas = cdCreateCanvas( CD_PRINTER, "SXY" );
00261 
00262 #else
00263   static char buffer[128];
00264   char* filename = tempnam( "/tmp/", "sxy_ps" );
00265   sprintf( buffer, "%s -o -pCD_A4" , filename);
00266   printer_canvas = cdCreateCanvas( CD_PS, buffer );
00267 #endif
00268   
00269   // O usuário pode ter cancelado a operação
00270   if (printer_canvas == NULL) {
00271      fprintf( stderr, "No printer_canvas created for printGraph()\n");
00272      return; 
00273   }
00274   drawChartsAt(printer_canvas, WITHOUT_DOUBLE_BUFFER);
00275   cdKillCanvas(printer_canvas);
00276 
00277 #ifdef WIN32
00278 #else
00279   if (ps_cmd != NULL) 
00280   { sprintf(buffer, ps_cmd, filename);
00281     system(buffer);
00282   }
00283 #endif
00284   redrawGraph();
00285 }
00286 
00287 // .......................................................................
00288 
00289 SXYTask* SXYGraph::getTask(int i) {
00290    assert(tasks_vector != NULL);
00291    return tasks_vector->getElement(i);
00292 }
00293 
00294 // .......................................................................
00295 
00296 int SXYGraph::getNumTasks(void) {
00297    if (tasks_vector == NULL) return 0;
00298    return tasks_vector->getLength();
00299 }
00300 
00301 // .......................................................................
00302 
00303 void SXYGraph::insertTask(SXYTask* tsk) {
00304    assert(tasks_vector != NULL);
00305    tasks_vector->insertElement(tsk);
00306 }
00307 
00308 // .......................................................................
00309 
00310 void SXYGraph::removeTask(SXYTask* tsk) {
00311    assert(tasks_vector != NULL);
00312    tasks_vector->removeElement(tsk);
00313 }
00314 
00315 // .......................................................................
00316 
00317 SXYChart* SXYGraph::getChart(int i) {
00318    assert(charts_vector != NULL);
00319    return charts_vector->getElement(i);
00320 }
00321 
00322 // .......................................................................
00323 
00324 int SXYGraph::getNumCharts(void) {
00325    if (charts_vector == NULL) return 0;
00326    return charts_vector->getLength();
00327 }
00328 
00329 // .......................................................................
00330 
00331 void SXYGraph::insertChart(SXYChart* cht) {
00332    assert(charts_vector != NULL);
00333    charts_vector->insertElement(cht);
00334 }
00335 
00336 // .......................................................................
00337 
00338 void SXYGraph::removeChart(SXYChart* cht) {
00339    assert(charts_vector != NULL);
00340    charts_vector->removeElement(cht);
00341 }
00342 
00343 // .......................................................................
00344 
00345 void SXYGraph::setStandartTasks(void) {
00346    this->insertTask(SXYTask::DEFAULT_MOVE_POINT_TASK);
00347    this->insertTask(SXYTask::DEFAULT_MOVE_LEGEND_TASK);
00348    this->insertTask(SXYTask::DEFAULT_ZOOM_IN_TASK);
00349    this->insertTask(SXYTask::DEFAULT_ADJUST_AXIS_TASK);
00350    this->insertTask(SXYTask::DEFAULT_EDIT_TEXT_TASK);
00351    this->insertTask(SXYTask::DEFAULT_CHANGE_COLORS_TASK);
00352 }
00353 
00354 // .......................................................................
00355 
00356 void SXYGraph::tryGridAdjust() {
00357   int n = getNumCharts();
00358   while(--n >= 0) {
00359      SXYChart* cht = getChart(n);
00360      assert(cht != NULL);
00361      cht->tryGridAdjust();
00362   }
00363 }
00364 
00365 // -----------------------------------------------------------------------
00366 // -----------------------------------------------------------------------
00367 // -----------------------------------------------------------------------
00368 
00369 // .......................................................................
00370 
00371 int SXYGraph::getChartOfEvent(int x, int y) {
00372   activateDisplayCanvas();
00373   // cdCanvas2Raster( &x, &y );
00374   // int cxsize, cysize;
00375   // cdGetCanvasSize( &cxsize, &cysize, NULL, NULL );
00376   int ncharts = getNumCharts();
00377   for (int c = 0; c < ncharts; c++) {
00378     SXYChart* cht = getChart(c);
00379     XYCartesian* xycart = cht->getXyGraph();
00380     int bxmin, bymin, bxmax, bymax;
00381     xycart->getViewport(bxmin, bxmax, bymin, bymax);
00382     // printf( "%d, %d -- %d %d %d %d\n", x, y, bxmin, bxmax, bymin, bymax);
00383     // fflush( stdout );
00384     if (bxmin < x && x < bxmax && bymin < y && y < bymax) return c;
00385   }
00386   return -1;
00387 }
00388 
00389 // .......................................................................
00390 
00391 void SXYGraph::activateDisplayCanvas(void) {
00392   assert(cd_canvas);
00393   if (cdActivate(cd_canvas) == CD_ERROR) {
00394      IupMessage( "Erro interno", "Falha na volta de desenho do gráfico!" );
00395   }
00396 }
00397 
00398 // .......................................................................
00399 
00400 SXYGraph* SXYGraph::getThis( Ihandle* handle ) {
00401    return (SXYGraph*) IupGetAttribute( handle, GRAPH_ATTR_NAME );
00402 }
00403 
00404 // .......................................................................
00405 
00406 int SXYGraph::iupLeaveCallback( Ihandle* h ) {
00407    SXYGraph* graph = getThis( h );
00408 
00409    int ntasks = graph->getNumTasks();
00410    for (int t = 0; t < ntasks; t++) {
00411      SXYTask* tsk = graph->getTask(t);
00412      assert (tsk);
00413      if ( tsk->mouseLeave(graph) == CALLBACK_TREATED ) return IUP_DEFAULT;
00414    }
00415 
00416   if (graph) graph->mouseLeave();
00417 
00418   return IUP_DEFAULT;
00419 }
00420 
00421 // .......................................................................
00422 
00423 int SXYGraph::iupEnterCallback( Ihandle* h ) {
00424    SXYGraph* graph = getThis( h );
00425 
00426    int ntasks = graph->getNumTasks();
00427    for (int t = 0; t < ntasks; t++) {
00428      SXYTask* tsk = graph->getTask(t);
00429      assert (tsk);
00430      if ( tsk->mouseEnter(graph) == CALLBACK_TREATED ) return IUP_DEFAULT;
00431    }
00432 
00433    if (graph) graph->mouseEnter();
00434    return IUP_DEFAULT;
00435 }
00436 
00437 // .......................................................................
00438 
00439 int SXYGraph::iupActionCallback( Ihandle* h ) {
00440    SXYGraph* graph = getThis( h );
00441    if (graph) graph->redrawGraph();
00442    return IUP_DEFAULT;
00443 }
00444 
00445 // .......................................................................
00446 
00447 int SXYGraph::iupMotionCallback(Ihandle* h, int x, int y, char *r) {
00448    SXYGraph* graph = getThis( h );
00449    if (!graph) return IUP_DEFAULT;
00450 
00451    int sft = isshift(r);
00452    int ctr = iscontrol(r);
00453    graph->activateDisplayCanvas();
00454    cdCanvas2Raster( &x, &y );
00455 
00456 
00457    int ntasks = graph->getNumTasks();
00458    for (int t = 0; t < ntasks; t++) {
00459      SXYTask* tsk = graph->getTask(t);
00460      assert (tsk);
00461      if (tsk->mouseMotion(graph, x, y, sft, ctr) == CALLBACK_TREATED) 
00462          return IUP_DEFAULT;
00463    }
00464 
00465    graph->mouseMotion(x, y, sft, ctr);
00466    return IUP_DEFAULT;
00467 }
00468 
00469 // .......................................................................
00470 
00471 int SXYGraph::iupButtonCallback(Ihandle* h, int b, int e, int x, int y, char *r) {
00472    SXYGraph* graph = getThis( h );
00473    if (!graph) return IUP_DEFAULT;
00474 
00475    int sft = isshift(r);
00476    int ctr = iscontrol(r);
00477    int but = (b == IUP_BUTTON1 ? 1 : b  == IUP_BUTTON2 ? 2 : 3 );
00478    graph->activateDisplayCanvas();
00479    cdCanvas2Raster( &x, &y );
00480 
00481    int ntasks = graph->getNumTasks();
00482    for (int t = 0; t < ntasks; t++) {
00483      SXYTask* tsk = graph->getTask(t);
00484      assert (tsk);
00485      if (e==1) {
00486        if (tsk->mouseClick(graph, but, x, y, sft, ctr) == CALLBACK_TREATED) 
00487           return IUP_DEFAULT;
00488      }
00489      else {
00490        if (tsk->mouseUnclick(graph, but, x, y, sft, ctr) == CALLBACK_TREATED) 
00491           return IUP_DEFAULT;
00492      }
00493    }
00494 
00495    if (e==1) graph->mouseClick(but, x, y, sft, ctr);
00496    else      graph->mouseUnclick(but, x, y, sft, ctr);
00497 
00498    /* Retorno ao IUP */
00499    return IUP_DEFAULT;
00500 }
00501 
00502 // .......................................................................
00503 
00504 int SXYGraph::iupResizeCallback( Ihandle* h, int width, int height ) {
00505    SXYGraph* graph = getThis( h );
00506    if (!graph) return IUP_DEFAULT;
00507    graph->activateDisplayCanvas();
00508    return IUP_DEFAULT;
00509 }
00510 

SXY
Tecgraf / PUC-Rio - Computer Graphics Technology Group