Logo Search packages:      
Sourcecode: magics++ version File versions  Download package

BaseDriver.cc

Go to the documentation of this file.
/******************************** LICENSE ********************************

 Copyright 2007 European Centre for Medium-Range Weather Forecasts (ECMWF)

 Licensed under the Apache License, Version 2.0 (the "License");
 you may not use this file except in compliance with the License.
 You may obtain a copy of the License at

    http://www.apache.org/licenses/LICENSE-2.0

 Unless required by applicable law or agreed to in writing, software
 distributed under the License is distributed on an "AS IS" BASIS,
 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 See the License for the specific language governing permissions and
 limitations under the License.

 ******************************** LICENSE ********************************/

/*! \file BaseDriver.cc
    \brief Implementation of driver base class.
    \author Graphics Section, ECMWF

    Started: Jan 2004

*/

#include <BaseDriver.h>

#include <Layout.h>
#include <Layer.h>
#include <Polyline.h>
#include <Text.h>
#include <BinaryObject.h>
#include <Colour.h>
#include <Arrow.h>
#include <Flag.h>
#include <ImportObject.h>
#include <Image.h>
#include <Symbol.h>
#include <PaperPoint.h>
//#include <InteractiveSet.h>
//#include <FrameLoop.h>
#include "AnimationRules.h"

#include <BaseDriverSymbols.h>
#include <BaseDriverWind.h>
#include <BaseDriverImages.h>

#include <System.h>

using namespace magics;

int BaseDriver::numFiles_ = 0;



//! Constructor for all drivers
/*!
  Main job is to initialise most variables and read font information
*/
00061 BaseDriver::BaseDriver():currentPage_(-1),fileName_(""),currentLayer_(""),currentGroup_(""),
        currentLineType_(M_SOLID),currentLineWidth_(-1), currentLineStyle_(1),currentColour_(Colour("white")),
      coordRatioX_(1),coordRatioY_(1),
      lastAreaHeightPercentage_(0.),lastAreaWidthPercentage_(0.),
      newPage_(true),newLayout_(true),external_(false),polylineAntialiasing_(false),disabled_(false),alphaEnabled_(false),obs_distance_(-1.),
      indexHatch_(0),currentShading_(M_SH_NONE),cmScale_(1.),
      xDeviceLength_(Translator<double, double>().magics("SUPER_PAGE_X_LENGTH")),
      yDeviceLength_(Translator<double, double>().magics("SUPER_PAGE_Y_LENGTH"))
{
      readFonts();

        //width in pixels  = cm * 2.54 * dpi
        //height in pixels = cm * 2.54 * dpi
/*        const string size = getSize();
        const float cmdpi = 2.54 * 72.;
        if(!magCompare(size,"a4"))
        {
            string::size_type posX = size.find_first_of("x");
            if(posX != string::npos)
            {
                const string first = size.substr(0,posX);
                string::size_type posCM = size.find_first_of("c",posX+1);
                if(posCM != string::npos) // assume CM
                {
                   float xcm=0.;
                   float ycm=0.;
                   istringstream is(first);
                   is>>xcm;
                   xDeviceLength_ = static_cast<int>(xcm * cmdpi);
                   const string second = size.substr(posX+1,posCM);
                   istringstream iy(second);
                   iy>>ycm;
                   yDeviceLength_ = static_cast<int>(ycm * cmdpi);
                }
                else   // assume pixels
                {
                   xDeviceLength_ = atoi(first.c_str());
                   const string second = size.substr(posX+1);
                   yDeviceLength_ = atoi(second.c_str());
                }
            }
            else
            {
                if     (magCompare(size,"a4")) {xDeviceLength_= 21.  * cmdpi; yDeviceLength_= 29.7 * cmdpi;}
                else if(magCompare(size,"a3")) {xDeviceLength_= 29.7 * cmdpi; yDeviceLength_= 42.  * cmdpi;}
            }
        }
*/
}

BaseDriver::~BaseDriver()
{
  FontMap_.clear();
}


//! Method set solid fill shading properties
/*
 \sa renderSimplePolygon
*/
00121 void BaseDriver::shade(const FillShadingProperties& properties)  const 
{
      currentShading_ = M_SH_SOLID;
      currentShadingProperties_ = &properties;
}

//! Method set hatch fill shading properties
/*
 \sa renderSimplePolygon
*/
00131 void BaseDriver::shade(const HatchShadingProperties& properties) const
{
      currentShading_ = M_SH_HATCH;
      currentShadingProperties_ = &properties;
}

//! Method set dot fill shading properties
/*
 \sa renderSimplePolygon
*/
00141 void BaseDriver::shade(const DotShadingProperties& properties)   const
{
      currentShading_ = M_SH_DOT;
      currentShadingProperties_ = &properties;
}

/*!
 \brief Method to print list of all generated files in the driver
*/
00150 void BaseDriver::printOutputName(const std::string & str) const
{
      if(getFilelist())
      {
            const SystemInfo info;
            fstream fs;
            if(numFiles_ == 0)
            {
                  fs.open(getFilelist_name().c_str(),fstream::out);
                  fs << "# "<< getMagicsVersionString()<< " "<<info.getHostName() <<" " << info.getTime()<< "\n";
            }
            else
                  fs.open(getFilelist_name().c_str(),fstream::out | fstream::app);

            fs << info.getTime()<< " "<<str<< "\n";
            fs.close();
            numFiles_++;
      }
}


//! Method to read font information
/*!
 A hash table is produce to map font names to file names of TTF
 files.

  \todo make this a singleton!?
*/
00178 void BaseDriver::readFonts() const
{
      const string s = getEnvVariable("MAGPLUS_HOME") + MAGPLUS_PATH_TO_SHARE_ + "Fonts.dat";
      ifstream psfile(s.c_str());

      if(psfile)
      {
            int   id;
            char  temp[128];
            char  magics_name[64];
            char  ps_name[128];
            char  ps_filename[128];
            char  ttf_filename[128];
            char  css_name[128];

            // read header (4 lines) and ignore
            psfile.getline(temp,128);psfile.getline(temp,128);
            psfile.getline(temp,128);psfile.getline(temp,128);

            while (!psfile.eof())
            {
                  magFont font;
                  psfile >> id >> magics_name >> ps_name >> ps_filename >> ttf_filename >> css_name;
                  font.id = id;
                  font.magics_name = magics_name;
                  font.ps_name = ps_name;
                  font.ps_filename = ps_filename;
                  font.ttf_filename = ttf_filename;
                  font.css_name = css_name;
                  FontMap_[string(magics_name)]= font;
            }
            psfile.close();
      }
      else Log::fatal() << "BaseDriver::readFonts() --> Cannot open Font file " << s << " ! No text can be plotted.\n";
}

/*! \brief formulating a filename

  This method is used to add the page number for multipage output,
  such in PostScriptDriver (if EPS or splitted), GDDriver (if not animated)
  and SVGDriver.

  It preserves the file name extension, and it needs it !!!
*/
00222 string BaseDriver::getFileName(const string &extension, const unsigned int no) const
{
      string ext = "."+extension;
      bool set      = false;
      bool full     = false;
      bool legacy   = false;

      string filename = getName();
      if(filename=="")
      {
        filename = getFullname();
        if(filename!="") full = true;
      }
      if(filename=="")
      {
        filename = getLegacyname();
        if(filename!="") legacy = true;
      }
      if(filename=="")
      {
        filename = extension;
        if(filename!="") set = true;
      }

      // name stays the same as given
      if( no==0 && (full || (legacy && extension=="ps")) ) return filename;
      if( no==0 )  { filename += ext; return filename;}
      if( external_ )   { filename += "_legend"+ext; return filename;}


      // if nothing is set
      if(filename=="") filename = "magics";

      if(full)
      {
            string::size_type pos = filename.find_last_of(".");
            if(pos != string::npos)
            {
                  const string f = filename.substr(0,pos);
                  const string t = filename.substr(pos);
                  ext = t;
                  filename = f;
            }
      }

      const int numberWidth = getNumberingwidth();

      if( (no > 1) || getFirstnumber() || legacy )
      {
            char *ostr;
            if(numberWidth==4)      {ostr=new char[5]; sprintf(ostr,"%04u",no);}
            else if(numberWidth==3) {ostr=new char[4]; sprintf(ostr,"%03u",no);}
            else if(numberWidth==2) {ostr=new char[3]; sprintf(ostr,"%02u",no);}
            else                    {ostr=new char[2]; sprintf(ostr,"%u",no);}
            filename += getSeparator()+ostr+ext;
            delete [] ostr;
      }
      else // if first page no number
      {
            filename += ext;
      }

      return filename;
}

/*!

  Overwritten in KMLDriver
  
  \sa Layer

*/
00294 MAGICS_NO_EXPORT void BaseDriver::redisplay(const Layer& layer) const 
{
      if(!magCompare(currentLayer_,layer.name()))
      {
            currentLayer_=layer.name();
            
            newLayer(layer);
            layer.visit(*this);
            closeLayer(layer);
      }
      else
            layer.visit(*this);
}


/*!
 \brief Method to read and execute binary file
 
 This method is implmented for performance in Metview 4 and WREP
 
*/
00315 void BaseDriver::redisplay(const BinaryObject& binary) const 
{
  ifstream in(binary.getPath().c_str());
  char mag [6];
  in.read((char *)(&mag), 6);
  if(strncmp( "MAGICS", mag,6) !=0 )
  {
        Log::error() << "Magics number of binary file " <<binary.getPath().c_str()<<" is wrong!\n"
                  << "   Please check endiness and if you gave the write filename."<< endl;
        return;
  }
  int version;
  in.read((char *)(&version), sizeof(int));
  cout << "BINARY version = "<<version<< endl;

  char c;
  while( in.get(c) )
  {
      int n;
      switch(c) {
      case 'T':
            float x;
            float y;
            float s;
            int len;
            { 
                  in.read((char *)(&x), sizeof(float));
                  in.read((char *)(&y), sizeof(float));
                  Text text;
                  PaperPoint pp(x,y);
                  text.push_back(pp);

                  float angle;
                  in.read((char *)(&angle), sizeof(float));
                  in.read((char *)(&s), sizeof(float));
                  bool bl;
                  in.read((char *)(&bl), sizeof(bool));
                  enum Justification horizontal;
                  enum VerticalAlign vertical;
                  in.read((char *)(&horizontal), sizeof(enum Justification));
                  in.read((char *)(&vertical), sizeof(enum VerticalAlign));
                  in.read((char *)(&len), sizeof(int));
                  char *tex = new char[len+1];
                  in.read(tex, sizeof(char)*len);
                  tex[len]='\0';

                  string str(tex);
                  text.addText(str,Colour("black"),s);
                  text.setBlanking(bl);
                  text.setJustification(horizontal);
                  text.setVerticalAlign(vertical);
                  text.setAngle(angle);
                  renderText(text);
                  delete [] tex;
            }
            break;

      case 'A':
            in.read((char *)(&n), sizeof(int));
            {
                  Arrow arrow;
                  double sc;
                  in.read((char *)(&sc), sizeof(double));
                  arrow.setScale(sc);
                  int index;
                  in.read((char *)(&index), sizeof(int));
                  arrow.setHeadIndex(index);
                  LineStyle ls;
                  in.read((char *)(&ls), sizeof(LineStyle));
                  arrow.setStyle(ls);
                  ArrowPosition ap;
                  in.read((char *)(&ap), sizeof(ArrowPosition));
                  arrow.setArrowPosition(ap);
                  int hi;
                  in.read((char *)(&hi), sizeof(int));
                  arrow.setHeadIndex(hi);
                  double hr;
                  in.read((char *)(&hr), sizeof(double));
                  arrow.setHeadRatio(hr);
                  float r,g,b;
                  in.read((char *)(&r), sizeof(float));
                  in.read((char *)(&g), sizeof(float));
                  in.read((char *)(&b), sizeof(float));
                  setNewColour(Colour(r,g,b));

                  for(int pts=0;pts<n;pts++)
                  {
                    double x,y;
                    in.read((char *)(&x), sizeof(double));
                    in.read((char *)(&y), sizeof(double));
                    PaperPoint p;
                    in.read((char *)(&p), sizeof(PaperPoint));
                    ArrowPoint ap(x, y, p);
                    arrow.push_back(ap);
                  } 
                  renderWindArrow(arrow);
            }
            break;
      case 'H':
            in.read((char *)(&n), sizeof(int));
            {
                  float *x = new float[n];
                  float *y = new float[n];
                  in.read((char *)(x), sizeof(float)*n);
                  in.read((char *)(y), sizeof(float)*n);
                  renderPolyline( n, x, y);
                  delete [] x;
                  delete [] y;
            }
            break;

      case 'B':
            in.read((char *)(&n), sizeof(int));
            {
                  float *x = new float[n];
                  float *y = new float[n];
                  in.read((char *)(x), sizeof(float)*n);
                  in.read((char *)(y), sizeof(float)*n);
                  renderPolyline2( n, x, y);
                  delete [] x;
                  delete [] y;
            }
            break;

      case 'S':
            in.read((char *)(&n), sizeof(int));
            {
                  float *x = new float[n];
                  float *y = new float[n];
                  in.read((char *)(x), sizeof(float)*n);
                  in.read((char *)(y), sizeof(float)*n);
                  renderSimplePolygon( n, x, y);
                  delete [] x;
                  delete [] y;
            }
            break;

      case 'W':
            float width;
            in.read((char *)(&width), sizeof(float));
            setNewLineWidth(width);
            break;

      case 'L':
            float w;
            LineStyle linestyle;
            in.read((char *)(&linestyle), sizeof(LineStyle));
            in.read((char *)(&w), sizeof(float));
            setLineParameters(linestyle, w);
            break;

      case 'C':
            float r,g,b;
            in.read((char *)(&r), sizeof(float));
            in.read((char *)(&g), sizeof(float));
            in.read((char *)(&b), sizeof(float));
            setNewColour(Colour(r,g,b));
            break;
      case 'N':
      //            cout<<"N"<< endl;
            startPage();
            break;
      case 'E':
      //            cout<<"E"<< endl;
            endPage();
            break;
      case 'P':
            {
                  Layout l;
                  double x,y,w,h,minx,miny,maxx,maxy;
                  in.read((char *)(&x), sizeof(double));
                  in.read((char *)(&y), sizeof(double));
                  in.read((char *)(&w), sizeof(double));
                  in.read((char *)(&h), sizeof(double));
                  in.read((char *)(&minx), sizeof(double));
                  in.read((char *)(&miny), sizeof(double));
                  in.read((char *)(&maxx), sizeof(double));
                  in.read((char *)(&maxy), sizeof(double));
                  l.x(x);
                  l.y(y);
                  l.width(w);
                  l.height(h);
                  l.minX(minx);
                  l.minY(miny);
                  l.maxX(maxx);
                  l.maxY(maxy);
                  project(l);
            }
            break;
      case 'U':
            unproject();
            break;
      }
   }
   in.close();
}


/*!
  \brief processing layouts
  This methods processes the Layout objects. It needs to be checked if a Layout is a new page or not.
  \sa Layout
*/
00518 MAGICS_NO_EXPORT void BaseDriver::redisplay(const Layout& layout) const 
{
      if(layout.childOfRoot()) startPage();  // New page detected

      project(layout);
      staLayouts_.push(&layout);
      layout.visit(*this);  // visit this layout!
      unproject();

      if(layout.childOfRoot())
      {
            endPage();
            vecPoints_.clear();
      }
}

/*!
  \brief processing standalone layouts
  This methods processes the Layout objects. It will mostly requires a new page!
  Only the KMLDriver will have the legend included.
  \sa Layout UnLayout
*/
00540 void BaseDriver::redisplay(const StandaloneLayout& layout) const
{
      external_=true;
      startAdditionalPage(layout);  // New page detected

      project(layout);
      staLayouts_.push(&layout);
      layout.visit(*this);  // visit this layout!
      unproject();

      endAdditionalPage();
        external_=false;
}

MAGICS_NO_EXPORT void BaseDriver::redisplay(const RootLayout& root) const
{
      root.visit(*this);  // visit this ROOT layout! 
}

/*!
 \brief Method to trigger rendering of animation step tree

 \sa OpenGLDriver 
*/
00564 void BaseDriver::redisplay(const StepRenderer& step) const
{
      Log::dev() << "BaseDriver::redisplay(const StepRenderer& step)"  << step << "--> needs implementing!" << endl;
}

void BaseDriver::redisplay(const Polyline& line) const
{
      if(line.isFilled())
      {
            setNewColour(line.getFillColour());
            vector<PaperPoint> points;
            const unsigned int size = line.size();
            for(unsigned int i=0;i<size;i++) points.push_back(line[i]);
            line.getShading()->draw(*this);
            renderSimplePolygon(points);
      }
      printLine(line);
}

00583 void BaseDriver::redisplay(const Arrow& arrow) const
{
      renderWindArrow(arrow); 
}

00588 void BaseDriver::redisplay(const Flag& flag) const
{
      renderWindFlag(flag);   
}

00593 void BaseDriver::redisplay(const ImportObject& object) const
{
      renderImage(object);
}

00598 void BaseDriver::redisplay(const Image& object) const
{
      renderCellArray(object);
}

00603 void BaseDriver::redisplay(const Text& text) const
{
      renderText(text);
}

00608 void BaseDriver::redisplay(const Symbol& symbol) const
{
      renderSymbols(symbol);
}

00613 void BaseDriver::redisplay(const TextSymbol& symbol) const 
{
      renderTextSymbols(symbol);
}

00618 void BaseDriver::redisplay(const ComplexSymbol& symbol) const 
{
      renderComplexSymbols(symbol);
}

void BaseDriver::redisplay(const TextItem& text, const ComplexSymbol& symbol) const
{
      renderTextItem(text, symbol);
}

void BaseDriver::redisplay(const SymbolItem& text, const ComplexSymbol& symbol) const
{
      renderSymbolItem(text, symbol);
}

void BaseDriver::redisplay(const FlagItem& text, const ComplexSymbol& symbol) const
{
      renderFlagItem(text, symbol);
}



/*
 \brief Least Square fit of a line.

 Returns the angle (in relation to horizon == 0 ).

 \sa printLine
*/
double BaseDriver::LSF(float *x,float *y, int i0) const
{
      double angle = 0.;
      double x_sum = 0.;
      double y_sum = 0.;
      const unsigned int n = 15;

      for(unsigned int r=0;r<n;r++)
      {
            x_sum += projectX(x[i0+r]);
            y_sum += projectY(y[i0+r]);
      }

      const double x_over_n = x_sum / n;
      const double y_over_n = y_sum / n;
      double sxx = 0;
      double sxy = 0;

      for(unsigned int r=0;r<n;r++)
      {
            const double xi = projectX(x[i0+r]) - x_over_n;
            const double yi = projectY(y[i0+r]) - y_over_n;
            sxx  += (xi*xi);
            sxy  += (xi*yi);
      }
      if(sxx != 0) angle = atan2( (sxy/sxx) ,1.);
      else Log::debug() << "BaseDriver: Devision through zero prevented in calculation of Label angle!" << endl;

      return angle;
}

/*!
  \brief Method plotting Polylines with Labels.


  \sa renderPolyline renderText

  \todo location memory for labels.
*/
00686 void BaseDriver::printLine(const Polyline &line) const
{
    const unsigned long n = line.size();
    if(n < 1) return;

    float *x      = new float[n];
    float *y      = new float[n];

    for(unsigned long s=0;s<n;s++)
    {
        x[s] = line[s].x();
        y[s] = line[s].y();
    }

    // render line - driver specific part
    if(line.getThickness()>0  && !(line.getColour()==Colour("NONE")) )
    {
      setNewColour(line.getColour());
      currentLineStyle_ = setLineParameters(line.getLineStyle(),line.getThickness());

      if(line.getAntiAliasing()) polylineAntialiasing_=true;
      renderPolyline(n, x, y);
      polylineAntialiasing_=false;
    }

    const unsigned int minimum_points_for_labelling = 16;  // must be at least -15 : see function LSF above

    if (line.getLabel().isVisible() && line.getLabel().getText() != "" && (n > minimum_points_for_labelling))
    {
    //const unsigned int minimum_points_for_labelling = 16;  // must be at least -15 : see function LSF above

    // Calculate how far apart the labels should be.
    // Our algorithm is to take the average of the width and height and divide by 2.
    // This should give us approximately 3 labels over the width of the page.
    
    assert(staLayouts_.empty() == false);
  
    const float  coords_range_x = staLayouts_.top()->maxX()-staLayouts_.top()->minX();
    const float  coords_range_y = staLayouts_.top()->maxY()-staLayouts_.top()->minY();

    //const float  coords_range_x = getBox(line.getBox())->getXmax() - getBox(line.getBox())->getXmin();
    //const float  coords_range_y = getBox(line.getBox())->getYmax() - getBox(line.getBox())->getYmin();
    const float  min_distance_between_labels = (coords_range_x + coords_range_y) / 4;
    const float  min_square_distance_between_labels = (min_distance_between_labels * min_distance_between_labels);
    float *labelx = new float[n];  // in theory, we shouldn't need this many entries...
    float *labely = new float[n];  // in theory, we shouldn't need this many entries...
    int num_labels = 0;
        unsigned int i = 1;
        // Store the minimum x,y corner, pretending that we're going to plot a label there.
        // We won't actually plot a label there though - it's just to make sure that
        // we don't plot one too close to that point.
        labelx [0] = -180.;
        labely [0] = -90.;
      //labelx [0] = getBox(line.getBox())->getXmin();
        //labely [0] = getBox(line.getBox())->getYmin();
        num_labels = 1;


      while(i < n-minimum_points_for_labelling)
      {
        const double angle = LSF(x,y,i);
        const double angle2 = LSF(x,y,i+1);
        if(fabs(angle-angle2)< 0.01)
        {
          const float THIS_X = x[i];
          const float THIS_Y = y[i];
          const float PREV_X = labelx[num_labels - 1];
          const float PREV_Y = labely[num_labels - 1];

          const double distance_squared = ((THIS_X - PREV_X) * (THIS_X - PREV_X)) + ((THIS_Y - PREV_Y) * (THIS_Y - PREV_Y));

          if (distance_squared > min_square_distance_between_labels)
          {
                // line fitting
                float pro_x = x[i+2];
                float pro_y = y[i+2];  // lines not needed
                // end of line fitting
            
                Text text;
            PaperPoint pp(pro_x,pro_y);         
            text.push_back(pp);

            const Label label= line.getLabel();

            text.addText(label.getText(),label.getFontColour(),label.getFontSize()); 
            text.setBlanking(label.getBlanking());
            text.setJustification(label.getJustification());
            text.setVerticalAlign(MHALF);
            text.setAngle(-setAngleY(angle));   

            renderText(text);

            labelx [num_labels] = x[i];
            labely [num_labels] = y[i];
            num_labels++;
           }
        }//angles are not the same
        i++;
        }
        delete [] labelx;
        delete [] labely;
    }// endif enough points for a label

    delete [] x;
    delete [] y;

    currentColour_ = Colour("none");
}

void BaseDriver::renderPolyline(vector<PaperPoint> &vP) const
{
      const unsigned int size = vP.size();
      float *x = new float[size];
      float *y = new float[size];
      for(unsigned int i=0;i<size;i++)
      {
            x[i] = vP[i].x();
            y[i] = vP[i].y();
      }
      renderPolyline(size,x,y);

      delete [] x;
      delete [] y;
}

void BaseDriver::renderPolyline2(vector<PaperPoint> &vP) const
{
      const unsigned int size = vP.size();
      float *x = new float[size];
      float *y = new float[size];
      for(int unsigned i=0;i<size;i++)
      {
            x[i] = projectX(vP[i].x());
            y[i] = projectY(vP[i].y());
      }
      renderPolyline2(size,x,y);

      delete [] x;
      delete [] y;
}

void BaseDriver::renderSimplePolygon(vector<PaperPoint> &vP) const
{
      const unsigned int size = vP.size();
      float *x = new float[size];
      float *y = new float[size];
      for(unsigned int i=0;i<size;i++)
      {
            x[i] = vP[i].x();
            y[i] = vP[i].y();
      }
      renderSimplePolygon(size,x,y);

      delete [] x;
      delete [] y;
}

/*!
 Class information are given to the output-stream.
*/
00846 void BaseDriver::print(ostream& out) const
{
      out << "BaseDriver";
}

string BaseDriver::getTmpName() const
{
      string stmp;
//    if(getTempdir()!="local") stmp=getTempdir();
//    string stmp = (tmpdir) ? tmpdir : tmp;
      stmp+= "magics_temp_ps_XXXXXX";
      char* mtmp = new char [stmp.length()+1];
      stmp.copy(mtmp,string::npos);
      mtmp[stmp.length()] = '\0';
#ifndef MAGICS_WINDOWS_CYGWIN
      const int m = mkstemp(mtmp);
      stmp = ( m ) ? mtmp : " ";
#endif
      delete [] mtmp;

      return stmp;
}

bool BaseDriver::renderCellArray(const Image& ) const
{
    Log::dev() << "BaseDriver::renderCellArray ..." << endl;
    return true;
}

bool BaseDriver::renderPixmap(float, float, float, float, int, int, unsigned char*, int, bool) const
{
    Log::dev() << "BaseDriver::renderPixmap(float, float, float, float, int, int, unsigned char*, int) const" << endl;
    return true;
}

Generated by  Doxygen 1.6.0   Back to index