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

SVGDriver.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 SVGDriver.cc
    \brief Implementation of SVGDriver.
    \author Graphics Section, ECMWF

    Started: Fri Oct 26 20:58:21 2007

*/

#include <SVGDriver.h>
#include <Polyline.h>
#include <Text.h>
#include <Image.h>
#include <Symbol.h>
#include <ImportObject.h>
//#include <InteractiveSet.h>

//! For generating SVGZ files
extern "C"{
#include <stdio.h>
#include <string.h>
#include <zlib.h>
00042 #define SET_BINARY_MODE(file)
#define CHUNK 16384
}

int gzip(FILE *source, FILE *dest, int level)
{
    int ret, flush;
    unsigned have;
    z_stream strm;
    unsigned char in[CHUNK];
    unsigned char out[CHUNK];

    /* allocate deflate state */
    strm.zalloc = Z_NULL;
    strm.zfree = Z_NULL;
    strm.opaque = Z_NULL;
    ret = deflateInit(&strm, level);
    if (ret != Z_OK)
        return ret;

    /* compress until end of file */
    do {
        strm.avail_in = fread(in, 1, CHUNK, source);
        if (ferror(source)) {
            (void)deflateEnd(&strm);
            return Z_ERRNO;
        }
        flush = feof(source) ? Z_FINISH : Z_NO_FLUSH;
        strm.next_in = in;

        /* run deflate() on input until output buffer not full, finish
           compression if all of source has been read in */
        do {
            strm.avail_out = CHUNK;
            strm.next_out = out;
            ret = deflate(&strm, flush);    /* no bad return value */
//            assert(ret != Z_STREAM_ERROR);  /* state not clobbered */
            have = CHUNK - strm.avail_out;
            if (fwrite(out, 1, have, dest) != have || ferror(dest)) {
                (void)deflateEnd(&strm);
                return Z_ERRNO;
            }
        } while (strm.avail_out == 0);
//        assert(strm.avail_in == 0);     /* all input will be used */

        /* done when last data in file processed */
    } while (flush != Z_FINISH);
//    assert(ret == Z_STREAM_END);        /* stream will be complete */

    /* clean up and return */
    (void)deflateEnd(&strm);
    return Z_OK;
}


#ifdef MAGICS_RASTER
#include <gd.h>
#endif


int svg_pattern_count=0;

using namespace magics;

/*!
  \brief Constructor
*/
00109 SVGDriver::SVGDriver() : groupString_(""),
                  group_counter_(0), showCoordinates_(false),
                  interactive_(false),line_visible_(true), interactiveCounter_(0)
{
  inkscape_=true;
}

/*!
  \brief Destructor
*/
00119 SVGDriver::~SVGDriver() 
{
}

/*!
  \brief Opening the driver
*/
00126 void SVGDriver::open()
{
}

/*!
  \brief Closing the driver
*/
00133 void SVGDriver::close()
{
}

/*!
  \brief starting a new page

  This method has to take care that previous pages are closed and that
  for formats with multiple output files a new file is set up.
*/
00143 MAGICS_NO_EXPORT void SVGDriver::startPage() const
{
      debugOutput("Page - START");
      dimensionX_ = getWidth();
      dimensionY_ = dimensionX_*getRatio();
      const int height = static_cast<int>(dimensionY_);
      const int width  = static_cast<int>(dimensionX_);

setCMscale(30.);

      currentPage_++;

      string filename = getFileName("svg",currentPage_+1);
      tmp_pFile_ = filename;

      pFile_.open(filename.c_str(),std::ios::out);
      svg_output_resource_list_.push_back(filename);

      if(!pFile_)
      {
            Log::fatal() << "SVGDriver::startPage() --> Cannot open SVG output file: " << filename << "\n";
            exit(1);
      }
//    pFile_ = org_pFile_;
      // pFile_.precision(3);
      // pFile_.setf(ios_base::fixed);

      pFile_
      // << "<?xml version=\"1.0\" standalone=\"no\"?>\n"
      // << "<!DOCTYPE svg PUBLIC \"-//W3C//DTD SVG 1.0//EN\" \"http://www.w3.org/TR/2001/REC-SVG-20010904/DTD/svg10.dtd\">\n"
//    << "<svg version=\"1.1\" encoding=\"UTF-8\" baseProfile=\"full\"\n"
      << "<svg version=\"1.1\" encoding=\"iso-8859-1\" baseProfile=\"full\"\n"
      << "xmlns=\"http://www.w3.org/2000/svg\"\n"
      << "xmlns:xlink=\"http://www.w3.org/1999/xlink\"\n"
      << "xmlns:ev=\"http://www.w3.org/2001/xml-events\"\n";

      if(inkscape_)
        pFile_ << "xmlns:sodipodi=\"http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd\"\n"
               << "xmlns:inkscape=\"http://www.inkscape.org/namespaces/inkscape\"\n"
               << "inkscape:version=\"0.46\"\n"
               << "inkscape:output_extension=\"org.inkscape.output.svg.inkscape\"\n";
      
      if(getWriteSize()) pFile_<< "width=\""<<width<<"px\" height=\""<<height<<"px\" "; 

      pFile_<< "viewBox=\"0 0 "<<width+1<<" "<<height+1<<"\"\n"
      << "xml:space=\"preserve\"\n" // preserveAspectRatio=\"xMidYMid meet\"\n"
//    << "shape-rendering=\"optimizeSpeed\" text-rendering=\"optimizeSpeed\""
      << "zoomAndPan=\"enable\" onload=\"OnLoadEvent(evt)\">\n"
      << "<title>"<<getTitle()<<"</title>\n";

      if(!getDesc().empty()) pFile_<< "<desc>"<<getDesc()<<"</desc>\n";
      if(!getMeta().empty()) pFile_<< "<metadata>"<<getMeta()<<"</metadata>\n";
            pFile_ << "<defs>\n";
      if(getGui())
      {
            pFile_ << " <clipPath id=\"clip_lupe\" shape-rendering=\"optimizeSpeed\">\n"
                   << "  <circle cx=\"0\" cy=\"0\" r=\"75\"/>\n"
                   << " </clipPath>\n";
      }
      pFile_ << "</defs>\n";

      pFile_<< "<g id=\"page\" transform=\"translate(0,"<<dimensionY_<<")\">\n";
}

MAGICS_NO_EXPORT void SVGDriver::startAdditionalPage(const StandaloneLayout& lay) const
{
      debugOutput("Extra page - START");

      pFile_.close();
      string fn = getFileName("svg" ,-2);
      pFile_.open(fn.c_str(),std::ios::out);

      if(!pFile_)
      {
            Log::fatal() << "SVGDriver::startAdditionalPage() --> Cannot open SVG output file for legend: " << lay.path() << "\n";
            exit(1);
      }
      svg_output_resource_list_.push_back(lay.path());

      pFile_
      << "<svg version=\"1.1\" encoding=\"iso-8859-1\" baseProfile=\"full\"\n"
      << "xmlns=\"http://www.w3.org/2000/svg\"\n"
      << "xmlns:xlink=\"http://www.w3.org/1999/xlink\"\n"
      << "xmlns:ev=\"http://www.w3.org/2001/xml-events\"\n";

      if(inkscape_)
        pFile_ << "xmlns:sodipodi=\"http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd\"\n"
             << "xmlns:inkscape=\"http://www.inkscape.org/namespaces/inkscape\"\n"
             << "inkscape:version=\"0.46\"\n"
             << "inkscape:output_extension=\"org.inkscape.output.svg.inkscape\"\n";

//    if(getWriteSize()) pFile_<< "width=\""<<width<<"px\" height=\""<<height<<"px\" ";

      pFile_<< "viewBox=\"0 0 "<<lay.outputWidth()+1<<" "<<lay.outputHeight()+1<<"\"\n"
      << "xml:space=\"preserve\"\n" // preserveAspectRatio=\"xMidYMid meet\"\n"
//    << "shape-rendering=\"optimizeSpeed\" text-rendering=\"optimizeSpeed\""
      << "zoomAndPan=\"enable\" >\n"
      << "<title>"<<getTitle()<<" Legend</title>\n";

      pFile_<< "<g id=\"page\" transform=\"translate(0,"<<lay.outputHeight()<<")\">\n";
}

MAGICS_NO_EXPORT void SVGDriver::endAdditionalPage() const
{
      pFile_ << "</g></svg>\n";
      pFile_.close();

      pFile_.open(tmp_pFile_.c_str(),std::ios::app);
      debugOutput("Extra page - END");
}


/*!
  \brief ending a page
 
  This method has to take care that for formats with multiple output 
  files are closed.
*/
00261 MAGICS_NO_EXPORT void SVGDriver::endPage() const
{
      group_counter_=0;
      debugOutput("Page - END");
      // needed for y-axis translation in beginning!
      pFile_      << "</g>\n";  // end of Menu 

      if(getGui())
      {
            // menu-on-off button
/*          pFile_      << "<g id=\"menu_button\" stroke=\"blue\" fill=\"blue\" >\n"
                  << " <polyline points=\"0,0 0,5 5,0\" width=\"1\" />\n"
                  << "</g>\n";
*/          pFile_ << "<g>\n"
                   << "<g id=\"menu\" visibility=\"visible\" fill=\"blue\" stroke=\"none\" font-size=\"10\""
                   << " fill-opacity=\"0.2\" stroke-opacity=\"0.8\">\n";

            // lupe button
/*          pFile_      << "<g id=\"lupe_button\" stroke=\"blue\" transform=\"translate(10 5)\" >\n"
                  << " <circle cx=\"0\" cy=\"11\" r=\"10\" fill=\"rgb(230,230,255)\" />\n"
                  << " <circle cx=\"-2\" cy=\"9\" r=\"4\"  fill=\"rgb(230,230,255)\" />\n"
                  << " <rect x=\"2\" y=\"12\" transform=\"rotate(45 2 12)\" fill=\"blue\" width=\"4\" height=\"2\"/>\n"
                  << "</g>\n";
*/
            // layer button
/*          pFile_      << "<g id=\"layers_button\" stroke=\"blue\" transform=\"translate(32 5)\" >\n"
                  << " <circle cx=\"0\" cy=\"11\" r=\"10\" fill=\"rgb(230,230,255)\" />\n"
                  << " <rect x=\"2\" y=\"12\" fill=\"blue\" width=\"4\" height=\"2\"/>\n"
                  << "</g>\n";
*/
            // Menu
            if(!layers_.empty())
            {
              pFile_    << "<g id=\"layers_menu\" visibility=\"visible\" transform=\"translate(43 5)\" >\n"
                        << " <text x=\"10\" y=\"17\">Layers:</text>\n";
              int offset = 55;
              for(vector<string>::iterator iter=layers_.begin(); iter != layers_.end();++iter)
              {
              pFile_ << "<g id=\"button_"<<*iter<<"\" transform=\"translate("<<offset<<" 0)\">\n"
                     << " <rect x=\"0\" y=\"0\"  rx=\"5\" ry=\"5\" fill=\"rgb(230,230,230)\" width=\"90\" height=\"23\"/>\n"
                     << " <text x=\"20\" y=\"17\" font-size=\"11\">"<<*iter<<"</text>\n"
                     << " <polyline id=\""<<*iter<<"_tick\" points=\"4,12 8,17 15,6\" width=\"4\" stroke=\"red\" visibility=\"visible\" fill=\"none\"/>\n"
                     << "</g>\n";
                     offset += 100;
              }
              pFile_ << "</g>\n";
            }
            pFile_ << "</g>\n";  // end of Menu
            pFile_ << "</g>\n"; 
      }
      if(getGui() || (interactiveCounter_>0) )
      {
            // Scripting - JAVASCRIPT
            pFile_      << "<script type=\"text/ecmascript\"><![CDATA[\n"
                  << "var slider=null, thumb=null, page=null, sliderActive = false;\nvar doc=null;\n"
                  
/*                << "function scaleup(evt)\n"
                  << "{\n"
                  << "\ttarget=evt.target;\n"
                  << "\tif(target!=null)\n\t{\n"
                  << "\t\ttarget.setAttributeNS(null,\"transform\",\"scale(2,2)\");\n"
      //          << "\t\ttarget.setAttributeNS(null,\"transform\",\"translate()\");\n"
                  << "\t}\n"
                  << "}\n"
                  << "function scaledown(evt)\n"
                  << "{\n"
                  << "\ttarget=evt.target;\n"
                  << "\tif(target!=null)\n\t{\n"
                  << "\t\ttarget.setAttributeNS(null,\"transform\",\"scale(1,1)\");\n"
      //          << "\t\ttarget.setAttributeNS(null,\"transform\",\"translate()\");\n"
                  << "\t}\n"
                  << "}\n"

                  << "function switchMenu(evt){\n"
                  << "\tl=document.getElementById(\"menu\")\n"
                  << "\tvar at=l.getAttributeNS(null,\"visibility\");\n"
                  << "\tif(at==\"visible\") {l.setAttributeNS(null,\"visibility\",\"hidden\");}\n"
                  << "\telse {l.setAttributeNS(null,\"visibility\",\"visible\");}\n"
                  << "}\n"
                  << "function switchLayers(evt){\n"
                  << "\tl=document.getElementById(\"layers_menu\")\n"
                  << "\tvar at=l.getAttributeNS(null,\"visibility\");\n"
                  << "\tif(at==\"visible\") {l.setAttributeNS(null,\"visibility\",\"hidden\");}\n"
                  << "\telse {l.setAttributeNS(null,\"visibility\",\"visible\");}\n"
                  << "}\n"
                  << "function switchLupe(evt){\n"
                  << "\tl=document.getElementById(\"lupe\")\n"
                  << "\tvar at=l.getAttributeNS(null,\"visibility\");\n"
                  << "\tif(at==\"visible\") {l.setAttributeNS(null,\"visibility\",\"hidden\");}\n"
                  << "\telse {l.setAttributeNS(null,\"visibility\",\"visible\");}\n"
                  << "}\n"
                  << "function moveLupe(evt){\n"
                  << "\tl=document.getElementById(\"lupe\")\n"
                  << "\tc=document.getElementById(\"page_mirror\")\n"
                  << "\tx=evt.clientX\n"
                  << "\ty=evt.clientY\n"
                  << "\tl.setAttribute(\"transform\",\"translate(\"+x+\" \"+y+\")\")\n"
                  << "\tc.setAttribute(\"transform\",\"scale(5) translate(\"+(-x)+\" \"+(-y)+\")\")\n"
                  << "}\n"
*/
                  << "function OnLoadEvent(evt)\n"
                  << "{\n"
                  << "  doc = evt.target.ownerDocument;\n"
                  << "  if(doc!=null)\n"
                  << "  {\n"
//                << "   pa = doc.getElementById(\"page\");\n"
      //          << "   doc.addEventListener(\"click\", moveLupe, false);\n"
      //          << "   lu = doc.getElementById(\"lupe_button\");\n"
      //          << "   lu.addEventListener(\"click\", switchLupe, false);\n"
      //          << "   me = doc.getElementById(\"menu_button\");\n"
      //          << "   me.addEventListener(\"click\", switchMenu, false);\n"
      //          << "   la = doc.getElementById(\"layers_button\");\n"
      //          << "   la.addEventListener(\"click\", switchLayers, false);\n";
<< "\n";

                  if(!layers_.empty())
                  {
                     for(vector<string>::iterator iter=layers_.begin(); iter != layers_.end();++iter)
                     {
                        pFile_      << "   but_"<<*iter<<" = doc.getElementById(\"button_"<<*iter<<"\");\n"
                              << "   but_"<<*iter<<".addEventListener(\"click\", toggle"<<*iter<<", false);\n";
//                            << "   but_"<<*iter<<".addEventListener(\"mousedown\", down"<<*iter<<", false);\n"
//                            << "   but_"<<*iter<<".addEventListener(\"mouseup\", up"<<*iter<<", false);\n";
                     }
                  }
/*                pFile_      << "  }\n"
                        << "}\n"
                        << "function setDimension(w,h) {\n"
                        << "\tdoc.documentElement.setAttribute(\"width\", w);\n"
                        << "\tdoc.documentElement.setAttribute(\"height\", h);\n"
                        << "}\n";
*/
                  if(!layers_.empty())
                  {
                     for(vector<string>::iterator iter=layers_.begin(); iter != layers_.end();++iter)
                     {
                        pFile_      << "function toggle"<<*iter<<"(evt){\n"
                              << "\tvar cl=doc.getElementById(\""<<*iter<<"\");\n"
                              << "\tvar sb=doc.getElementById(\""<<*iter<<"_tick\");\n"
                              << "\tvar at=sb.getAttributeNS(null,\"visibility\");\n"
                              << "\tif(at==\"visible\") {sb.setAttributeNS(null,\"visibility\",\"hidden\");cl.setAttributeNS(null,\"visibility\",\"hidden\");}\n"
                              << "\telse {sb.setAttributeNS(null,\"visibility\",\"visible\");cl.setAttributeNS(null,\"visibility\",\"visible\");}\n"
//                            << "}\n"
//                            << "function down"<<*iter<<"(evt){\n"
//                            << "\tvar cl=doc.getElementById(\""<<*iter<<"\");\n"
//                            << "}\n"
//                            << "function up"<<*iter<<"(evt){\n"
//                            << "\tvar cl=doc.getElementById(\""<<*iter<<"\");\n"
                              << "}\n";
                     }
                  }

                  pFile_      << "]]></script>\n";
      }
/*
      if(getGui())
      {
            pFile_ << "<g id=\"lupe\" visibility=\"hidden\" transform=\"translate(55, -4)\">\n"
                   << " <circle cx=\"0\" cy=\"0\" r=\"75\" fill=\"white\" stroke=\"none\"/>\n"
                   << " <g clip-path=\"url(#clip_lupe)\">\n"
                   << "  <use id=\"page_mirror\" xlink:href=\"#page\" transform=\"scale(3, 3) translate(-55, 4)\"/>\n"
                   << " </g>\n"
                   << " <circle cx=\"0\" cy=\"0\" r=\"75\" fill=\"none\" stroke=\"black\" stroke-width=\"5\"/>\n"
                   << "</g>\n";
      }
*/    pFile_ << "</svg>\n";
      pFile_.close();

      layers_.clear();

      //
      // code to compress for SVGZ
      //
//    if(getCompress() && !svg_output_resource_list_.empty())
      {
/*          FILE * input_file;
            if ((input_file = fopen(fileName_.c_str(), "r")) == NULL)
                  fprintf(stderr, "Cannot open %s\n", fileName_.c_str());

            fileName_ = getFileName("svgz");
            FILE * output_file;
            if ((output_file = fopen(fileName_.c_str(), "w")) == NULL)
                  fprintf(stderr, "Cannot open %s\n", fileName_.c_str());

            gzip(input_file, output_file, Z_DEFAULT_COMPRESSION);
*/
/*          if (!getDebug())
            {
                  stringarray::iterator it    = svg_output_resource_list_.begin();
                  stringarray::iterator itend = svg_output_resource_list_.end();
                  for(; it != itend; it++)
                  {
                        remove((*it).c_str());
                  }
                  printOutputName("SVG svgz "+fileName_);
            }
*/    }// Zipping ---> SVGZ
//    else
      {
            stringarray::iterator it    = svg_output_resource_list_.begin();
            stringarray::iterator itend = svg_output_resource_list_.end();
            for(; it != itend; it++)
            {
                  printOutputName("SVG misc "+(*it));
            }
      }
      newLayout_ = true;
}

/*!
  \brief project to a new Layout

  This method will update the offset and scale according to the new Layout given.

  \sa Layout
*/
00477 MAGICS_NO_EXPORT void SVGDriver::project(const magics::Layout& layout) const
{
      debugOutput("Layout - "+layout.name()+" START");
Log::debug() <<"PROJECT "<<layout.name()<<" "<<dimensionX_<<" w: "<< layout.width()<<" x: "<< layout.x()<< endl;
      dimensionStack_.push(dimensionX_);
      dimensionStack_.push(dimensionY_);
      scalesX_.push(coordRatioX_);
      scalesY_.push(coordRatioY_);

      const float Xoff  = layout.x()      * 0.01 * dimensionX_;
      const float Yoff  = layout.y()      * 0.01 * dimensionY_;
      dimensionX_       = layout.width()  * 0.01 * dimensionX_;
      dimensionY_       = layout.height() * 0.01 * dimensionY_;

      const float sumX = layout.maxX() - layout.minX();
      const float sumY = layout.maxY() - layout.minY();

      if( sumX!=0 && sumY!=0 )
      {
            coordRatioX_ =  dimensionX_/sumX;
            coordRatioY_ =  dimensionY_/sumY;
      }

//    if(box->getClip())
//    {
//          pFile_      << "<clipPath id=\"clip_"<<area<<"\">\n"
//                << " <path d=\"M"<<projectX(Xmin)<<" "<<projectY(-Ymin)<<"l"<< projectX(sumX)<<" 0l0 "<<-projectY(sumY)<<"l"<<-projectX(sumX)<<" 0l0 "<<projectY(sumY)<<"\"/>\n"
//                << "</clipPath>\n"; 
//    }
const float x_set = Xoff+projectX(-layout.minX());
const float y_set = Yoff+projectY(-layout.minY());

group_counter_++;

if(group_counter_>2)
{
        pFile_ << "<g id=\""<<layout.name()<<"\" transform=\"translate("<<x_set <<","<<setY(y_set) <<")\"";

//    if(showCoordinates_ && area=="drawing_area") pFile_ << " onmouseover=\"setLonScale("<<coordRatioX_<<");showCoords(evt)\"";

//    if(box->getClip()) pFile_ << " clip-path=\"url(#clip_"<<area<<")\"";
      pFile_ << ">\n";
//    group_project_=true;
}
//else
//  group_project_=false;

//    if(showCoordinates_ && area=="drawing_area")
//          pFile_      << "<rect x=\""<<Xmin<<"px\" y=\""<<setY(-Ymin)<<"px\" width=\""<<sumX<<"px\" height=\""<<sumY<<"px\" fill=\"white\"/>\n";
}

MAGICS_NO_EXPORT void SVGDriver::unproject() const
{
      closeGroup();

      dimensionY_ = dimensionStack_.top();dimensionStack_.pop();
      dimensionX_ = dimensionStack_.top();dimensionStack_.pop();
      coordRatioX_  = scalesX_.top();scalesX_.pop();
      coordRatioY_  = scalesY_.top();scalesY_.pop();
      if(group_counter_>2)
            pFile_ << "</g>\n";
      group_counter_--;
      debugOutput("Layout - END");
}


/*!
  \brief setup a new layer

  This method will setup a new layer. Layers enable overlays of entities
  of information.
*/
00549 MAGICS_NO_EXPORT void SVGDriver::newLayer(const Layer& ) const
{
      closeGroup();

      debugOutput("Layer - "+currentLayer_+" START");
      pFile_ << "<g ";
      if(inkscape_)
        pFile_ << "inkscape:groupmode=\"layer\" inkscape:label=\""<<currentLayer_<<"\" ";
      pFile_ << "id=\""<<currentLayer_<<"\">\n";
      layers_.push_back(currentLayer_);
}

/*!
  \brief close the current layer

  This method will close an existing layer. 

*/
00567 MAGICS_NO_EXPORT void SVGDriver::closeLayer(const Layer& ) const
{
      closeGroup();

      pFile_ << "</g>\n";
      debugOutput("Layer - "+currentLayer_+" END");
}

//MAGICS_NO_EXPORT void SVGDriver::renderInteractiveBegin(const InteractiveBegin& interactive) const
//{
/*
      InteractiveBegin::iterator iter = interactive.begin();

      for( ; iter != interactive.end(); iter++ )
      {
            Log::dev()<< "string: " << iter->first << endl;
      }
*/
/*    closeGroup();

      if( !magCompare(currentBox_,"non") ) unprojectBox();
      debugOutput("renderInteractiveBegin");
      pFile_ << "<g onmouseover=\"scaleup(evt);\" onmouseout=\"scaledown(evt);\" id=\"int"<<interactiveCounter_<<"\" fill=\"none\" transform=\"scale(1,1)\" >\n";
      interactiveCounter_++;
      interactive_=true;
}

MAGICS_NO_EXPORT void SVGDriver::renderInteractiveEnd(const InteractiveEnd&) const
{
      debugOutput("renderInteractiveEnd");
      if( !magCompare(currentBox_,"non") ) unprojectBox();
      pFile_ << "</g>"<<endl;
      interactive_=false;
}
*/

MAGICS_NO_EXPORT void SVGDriver::openGroup(string g) const
{
      if(!magCompare(g,groupString_))
      {
            closeGroup();
            pFile_      << "<g "<<g<<" >" <<endl;
            groupString_ = g;
      }
}

MAGICS_NO_EXPORT void SVGDriver::closeGroup() const
{
      if(!groupString_.empty())
      {
            pFile_      << "</g>"<<endl;
            groupString_="";
      }
}


/*!
  \brief sets a new colour

  This colour stays the default drawing colour until the painting in the 
  current box is finished.

  \sa Colour
*/
00631 MAGICS_NO_EXPORT void SVGDriver::setNewColour(const Colour &colour) const
{
      if(currentColour_ == colour) return;
      currentColour_ = colour;
}

/*!
  \brief sets a new line width

  This line width stays the default width until the painting in the 
  current box is finished.

  \sa setLineParameters()
*/
00645 MAGICS_NO_EXPORT void SVGDriver::setNewLineWidth(const float width) const
{
      currentLineWidth_ = width;
}

/*!
  \brief sets new properties of how lines are drawn

  These properties stay the default until the painting in the 
  current box is finished.

  \sa LineStyle

  \param linestyle Object describing the line style
  \param w width of the line

*/
00662 MAGICS_NO_EXPORT int SVGDriver::setLineParameters(const LineStyle linestyle, const float w) const
{
      const float wid = w*0.5;
      const float widi = (wid > 1) ? wid : 1;
      currentLineType_ = linestyle;

      ostringstream stream;
      stream  << "stroke-width=\""<<wid<<"px\" ";
      if(currentColour_.red()*currentColour_.green()*currentColour_.blue()<0)
      {
            stream      << "stroke=\"none\"";
            line_visible_=false;
      }
      else
      {
            line_visible_=true;
            if(currentColour_.alpha() < 1.) stream    << "stroke-opacity=\""<<currentColour_.alpha()<<"\" ";
            stream      << "stroke=\"rgb("
                  << static_cast<int>(currentColour_.red()  *255) << ","
                  << static_cast<int>(currentColour_.green()*255) << ","
                  << static_cast<int>(currentColour_.blue() *255) << ")\"";
      }
      stream  << " fill=\"none\"";

      if(currentLineType_==M_DASH)            stream  << " stroke-dasharray=\""<<2*widi<<","<<2*widi<<"\"";
      else if(currentLineType_==M_DOT)        stream  << " stroke-dasharray=\""<<1*widi<<","<<2*widi<<"\"";
      else if(currentLineType_==M_CHAIN_DASH) stream  << " stroke-dasharray=\""<<4*widi<<","<<2*widi<<","<<2*widi<<","<<2*widi<<"\"";
      else if(currentLineType_==M_CHAIN_DOT)  stream  << " stroke-dasharray=\""<<4*widi<<","<<2*widi<<","<<2*widi<<","<<2*widi<<","<<2*widi<<"\"";

      openGroup(stream.str());
      return 0;
}

/*!
  \brief renders polylines

  This method renders a polyline given as two float arrays. The two 
  arrays given as X and Y values have to be at least the length of
  <i>n</i>. All values beyond <i>n</i> will be ignored. The style is
  determined by what is described in the current LineStyle.

  \sa setLineParameters()
  \param n number of points
  \param x array of x values
  \param y array of y values
*/
00708 MAGICS_NO_EXPORT void SVGDriver::renderPolyline(const int n, float *x, float *y) const
{
  if(!line_visible_) return;
  if(n>1)
  {
      float old_x = projectX(x[0]);
      float old_y = setY(projectY(y[0]));
      pFile_ << "<path d=\"M"<<old_x<< " " << old_y;

      for(int is=1;is<n;is++)
      {
            const float x2 = projectX(x[is]);
            const float y2 = setY(projectY(y[is]));
            const float diffX = x2-old_x;
            const float diffY = y2-old_y;

            pFile_ <<"l"<< diffX <<" "<< diffY;
            old_x = x2;
            old_y = y2;
      }
      pFile_      << "\" />\n";
  }
}


/*!
  \brief renders a single line

  This method renders a polyline with two points.The style is
  determined by what is described in the current LineStyle.

  \sa setLineParameters()
  \param n number of points
  \param x array of x values
  \param y array of y values
*/
00744 MAGICS_NO_EXPORT void SVGDriver::renderPolyline2(const int n, float* x, float* y) const
{
      if(!line_visible_) return;
      if(n != 2) return;
      pFile_ << "<path d=\"M"<<x[0]<< " " <<setY(y[0])<<"L"<< x[1] <<" "<< setY(y[1]) << "\" />\n";
}

/*!
  \brief renders a filled polygon

  This method renders a filled polygon. The style is
  determined by what is described in the current LineStyle.

  \sa setLineParameters()
  \param n number of points
  \param x array of x values
  \param y array of y values
*/
00762 MAGICS_NO_EXPORT void SVGDriver::renderSimplePolygon(const int n, float* x, float* y) const
{
      closeGroup();
      debugOutput("renderSimplePolygon");
      if(n<2) return;
      if(currentColour_.red()*currentColour_.green()*currentColour_.blue()<0) return;

      int count = 1;
      float old_x = projectX(x[0]);
      float old_y = setY(projectY(y[0]));
      
      ostringstream stream;
      stream  <<" d=\"M"<<old_x<< " " << old_y;

      for(int is=1;is<n;is++)
      {
            const float xx = projectX(x[is]);
            const float yy =setY(projectY(y[is])) ;
            const float diffX = xx-old_x;
            const float diffY = yy-old_y;
            
//          if( fabs(diffX)>0.02 && fabs(diffY)>0.02 )
            {
                  stream <<"l"<< diffX <<" "<< diffY;
                  old_x = xx;
                  old_y = yy;
                  count++;
            }
      }

//    if(!interactive_) stream  << "pointer-events=\"none\" ";

      if(count > 3)
      {
            if(currentShading_==M_SH_DOT)
            {
                  pFile_  << "<pattern id=\"D_"<<svg_pattern_count<<"\" patternUnits=\"userSpaceOnUse\" x=\"0\" y=\"0\" width=\"10\" height=\"10\">\n"
                          << "   <rect x=\"3\" y=\"3\" width=\"3\" height=\"3\" stroke=\"none\" fill=\"rgb("
                        << static_cast<int>(currentColour_.red()  *255) << ","
                        << static_cast<int>(currentColour_.green()*255) << ","
                        << static_cast<int>(currentColour_.blue() *255) << ")\" ";
                  if(currentColour_.alpha() < 1.) pFile_    << "fill-opacity=\""<<currentColour_.alpha()<<"\" ";
                  pFile_  << "/>\n"
                          << "</pattern>\n"
                          << "<path fill=\"url(#D_"<<svg_pattern_count<<")\" stroke=\"none\" "
                        << stream.str() <<"\" />\n";
                  svg_pattern_count++;
            }
            if(currentShading_==M_SH_HATCH)
            {
                  const HatchShadingProperties *pro = (HatchShadingProperties*)currentShadingProperties_;
                  indexHatch_ = pro->index_;
                  const int density = (int)(1./pro->density_*150);

                  pFile_  << "<pattern id=\"H_"<<svg_pattern_count
                        <<"\" patternUnits=\"userSpaceOnUse\" x=\"0\" y=\"0\" width=\""<<density<<"\" height=\""<<density<<"\">\n"
                        << " <g stroke=\"rgb("
                        << static_cast<int>(currentColour_.red()  *255) << ","
                        << static_cast<int>(currentColour_.green()*255) << ","
                        << static_cast<int>(currentColour_.blue() *255) << ")\">\n";

                  if(indexHatch_==1 || indexHatch_==3) // horizontal
                  {
                        pFile_ << "  <polyline points=\"0,"<<density*.5<<" "<<density<<","<<density*.5<<"\"\n/>";
                  }
                  if(indexHatch_==2 || indexHatch_==3)
                  {
                        pFile_ << "  <polyline points=\""<<density*.5<<",0 "<<density*.5<<","<<density<<"\"\n/>";
                  }
                  if(indexHatch_==4 || indexHatch_==6)
                  {
                        pFile_ << "  <polyline points=\"0,0 "<<density<<","<<density<<"\"\n/>";
                  }
                  if(indexHatch_==5 || indexHatch_==6)
                  {
                        pFile_ << "  <polyline points=\""<<density<<","<<density<<" 0,0\"\n/>";
                  }
                  pFile_      << " </g>\n</pattern>\n"
                        << "<path fill=\"url(#H_"<<svg_pattern_count<<")\" stroke=\"none\" "
                        << stream.str() <<"\" />\n";
                  svg_pattern_count++;
            }
            else
            {
                  pFile_      <<"<path fill=\"rgb("
                        << static_cast<int>(currentColour_.red()  *255) << ","
                        << static_cast<int>(currentColour_.green()*255) << ","
                        << static_cast<int>(currentColour_.blue() *255) << ")\" "
                        << "stroke=\"rgb("
                        << static_cast<int>(currentColour_.red()  *255) << ","
                        << static_cast<int>(currentColour_.green()*255) << ","
                        << static_cast<int>(currentColour_.blue() *255) << ")\" "
                        << stream.str() <<"\" />\n";
            }
      }
}

/*!
  \brief renders text strings

  This method renders given text strings.

  \note As of version 2.0 there are two forms of describing text in Text.

   The'dy' parameter is used to shift text vertically because the 'basline-shift'
   parameter does not work in Firefox 1.5 + 2.0.

  \sa Text
  \param text object containing the strings and their description
*/
00872 MAGICS_NO_EXPORT void SVGDriver::renderText(const Text& text) const
{
  if(text.empty()) return;

  float text_scale = 0.6;  // for Firefox 2

  const vector<NiceText>& niceT = text.getNiceText();
  if(niceT.empty()) return;

  Justification horizontalAlign     = text.getJustification();
  string justification = "middle";
  if     ( horizontalAlign==MLEFT  ) justification = "start";
  else if( horizontalAlign==MRIGHT ) justification = "end";

  VerticalAlign verticalAlign = text.getVerticalAlign();
  double vertical = 0.;

  unsigned int noTexts = text.size();
  vector<NiceText>::const_iterator niceTextEnd = text.textEnd();

  for(unsigned int tex=0;tex<noTexts;tex++)  // for all sting COORDINATES
  {
      vector<NiceText>::const_iterator niceText = text.textBegin();

      for(;niceText<niceTextEnd;niceText++)
      {
            const MagFont magfont = (*niceText).font();
            setNewColour(magfont.colour());
            const float dheight = magfont.size()*text_scale;
            const string style  = (magfont.style()=="") ? "normal": magfont.style();
            const string font   = magfont.name()+"_"+style;

            if (verticalAlign==MBASE )       vertical = dheight *  .15;
            else if (verticalAlign==MTOP)    vertical = dheight * 1.0;
            else if (verticalAlign==MHALF)   vertical = dheight *  .5;
// default  else if (verticalAlign==MBOTTOM) vertical = 0.;
//          vertical = -vertical/dheight *100;

            fontMapIter iter = FontMap_.find(font);
            string ttf;
            if(iter!=FontMap_.end())
                  ttf = iter->second.css_name;
            else
            {
                  ttf = FontMap_["sansserif_normal"].css_name; // if not found get default
                  Log::warning() << "SVGDriver: Font "<< font << " is not registered! Default font is used."<< endl;
            }

            double xxx = projectX(text[tex].x());
            double yyy = setY(projectY(text[tex].y()));

            if(niceText==text.textBegin())
            {
               if(tex==0)
               {
                  ostringstream stream;
                  stream  << "text-anchor=\""<<justification<< "\"";
                  if(text.getAngle()!=0)
                        stream << " transform=\"rotate("<<text.getAngle()*57.29577951<<","<<xxx<<","<<yyy<<")\"";
                  stream <<" font-size=\""<<dheight<<"cm\" font-family=\""<< ttf << "\" "
//                       <<"stroke=\"rgb("<<currentColour_.red()*255<<","<<currentColour_.green()*255<<","<<currentColour_.blue()*255<<")\" "
                         <<"fill=\"rgb("<<static_cast<int>(currentColour_.red()*255)<<","<<static_cast<int>(currentColour_.green()*255)<<","
                         << static_cast<int>(currentColour_.blue()*255)<<")\"";
                  openGroup(stream.str());
               }

               pFile_ << "<text x=\""<<xxx<<"\" y=\""<<yyy<<"\"";
               if(text.getBlanking())
                     pFile_ << " background-color=\"white\"";
      //       pFile_ << " baseline-shift=\""<<vertical<<"%\">"<<(*niceText).text();
               pFile_ << "><tspan dy=\""<<vertical<<"cm\">"<<(*niceText).text()<<"</tspan>";
            }
            else
            {
              pFile_ <<"\n<tspan "
                  <<"font-size=\""<<dheight<<"cm\" font-family=\""<< ttf << "\" "
//                <<"stroke=\"rgb("<<currentColour_.red()*255<<","<<currentColour_.green()*255<<","<<currentColour_.blue()*255<<")\" "
                  <<"fill=\"rgb("<<static_cast<int>(currentColour_.red()*255)<<","<<static_cast<int>(currentColour_.green()*255)<<","
                  << static_cast<int>(currentColour_.blue()*255)<<")\""
                  <<">"<<(*niceText).text()<<"</tspan>";
            }
      }// end for all strings
      pFile_ <<"</text>\n";
   }// end for all co-ordinates
//   pFile_ <<"</g>\n";
}

/*!
  \brief drawing a circle

  This method renders given text strings.

  The meaning of the last parameter <i>s</i> is as follows:
     - 0-8 determines how many quarters of the circle are filled. Starting from the top clock-wise.
     - 9 fills the whole circle but leaves a vertical bar empty in the middle of the circle.

  \param x X Position
  \param y Y Position
  \param r Radius of circle
  \param s Style which determines how the circle is shaded
*/
00973 MAGICS_NO_EXPORT void SVGDriver::circle(const float x, const float y, const float r, const int s) const
{
      const int cx =      static_cast<int>(projectX(x));
      const int cy = setY(static_cast<int>(projectY(y)));

      ostringstream stream;

      if(s < 8 && s >= 0)
      {
            stream  << "stroke=\"rgb("
                  << static_cast<int>(currentColour_.red()  *255) << ","
                  << static_cast<int>(currentColour_.green()*255) << ","
                  << static_cast<int>(currentColour_.blue() *255) << ")\""
                  << " fill=\"none\"";
            openGroup(stream.str());

            if(s==0)
            {
             pFile_     << "<circle cx=\""<<cx<<"\" cy=\""<<cy<<"\" r=\""<<r<<"\"/>\n";
            }
            else
            {
             const short  i   = (s<4) ? 1 : 0;
             const double rad = s*0.7853981634*r;
             pFile_     << "<path d=\"M"<<cx<<" "<<cy-r<<" A"<<r<<","<<r<<" 0 "<<i<<" 1 "
                  << cx+cos(rad)<<" "<<cy+sin(rad)<<"\" "
                  << "fill=\"rgb("
                  << static_cast<int>(currentColour_.red()  *255) << ","
                  << static_cast<int>(currentColour_.green()*255) << ","
                  << static_cast<int>(currentColour_.blue() *255) << ")\""
                  <<"/>\n"
                  << "<circle cx=\""<<cx<<"\" cy=\""<<cy<<"\" r=\""<<r<<"\"""/>\n";
            }
      }
      else if(s==8)
      {
            stream  << "stroke=\"rgb("
                  << static_cast<int>(currentColour_.red()  *255) << ","
                  << static_cast<int>(currentColour_.green()*255) << ","
                  << static_cast<int>(currentColour_.blue() *255) << ")\""
                  << " fill=\"rgb("
                  << static_cast<int>(currentColour_.red()  *255) << ","
                  << static_cast<int>(currentColour_.green()*255) << ","
                  << static_cast<int>(currentColour_.blue() *255) << ")\"";
            openGroup(stream.str());

            pFile_      << "<circle cx=\""<<cx<<"\" cy=\""<<cy<<"\" r=\""<<r<<"\"/>\n";
      }
      if(s==9)
      {
            stream  << "stroke=\"rgb("
                  << static_cast<int>(currentColour_.red()  *255) << ","
                  << static_cast<int>(currentColour_.green()*255) << ","
                  << static_cast<int>(currentColour_.blue() *255) << ")\""
                  << " fill=\"rgb("
                  << static_cast<int>(currentColour_.red()  *255) << ","
                  << static_cast<int>(currentColour_.green()*255) << ","
                  << static_cast<int>(currentColour_.blue() *255) << ")\"";
            openGroup(stream.str());
            pFile_      << "<circle cx=\""<<cx<<"\" cy=\""<<cy<<"\" r=\""<<r<<"\"/>\n"
                  << "<polyline points=\"0,"<<r*.9<<" 0,"<<-r*.9<<"\" width=\"2\" stroke=\"white\" fill=\"white\"/>"<<endl;
      }

}

/*!
  \brief render pixmaps

  This method renders pixmaps. These are used for cell shading and raster input (GIFs and PNGs).

  \sa renderCellArray()

  \param x0 x of lower corner
  \param y0 y of lower corner
  \param x1 x of higher corner
  \param y1 y of higher corner
  \param w width of pixmap
  \param h height of pixmap
  \param pixmap contents

*/
01054 MAGICS_NO_EXPORT bool SVGDriver::renderPixmap(float x0,float y0,float x1,float y1,
                                            int w,int h,unsigned char* pixmap,int,bool ) const
{
      unsigned char *p = pixmap;    
      const float dx =  (x1 - x0)/w;
      const float dy = -(y1 - y0)/h;   // Minus needed for Y axis correction

      const float X0 = x0;
      const float Y0 = y0;

      debugOutput("Pixmap - START");
      pFile_      << "<g pointer-events=\"none\" >\n";

      for(int i=h-1;i>=0;i--)
      {
            for(int j=0;j<w; x0+=dx,j++)
            {
                  const int r = (int) *(p++);
                  const int g = (int) *(p++);
                  const int b = (int) *(p++);

                  const int x0 = static_cast<int>( X0+(j*dx) );
                  const int y0 = static_cast<int>( Y0+(i*dy) );

                  pFile_      << " <rect x=\""<<x0<<"\" y=\""<<setY(y0)<<"\" width=\""<<dx<<"\" height=\""<<dy<<"\""
                        << " fill=\"rgb("<< r << ","<< g << "," << b << ")\" "<< "stroke=\"none\" />\n";
            }
            x0 = X0;
            y0 += dy;
      }
      pFile_      << "</g>\n";
      debugOutput("Pixmap - END");
      return true;
}

/*!
  \brief render cell arrays

  This method renders cell arrays, also called images in Magics language. These are 
  mainly used for satellite data.

  \sa renderPixmap()

  \param image Object containing an image
*/
01099 MAGICS_NO_EXPORT bool SVGDriver::renderCellArray(const Image& image) const
{
      ColourTable &lt  = image.getColourTable(); 
      const int width  = image.getNumberOfColumns();
      const int height = image.getNumberOfRows();
      const float x0 = projectX(image.getOrigin().x());
      const float y0 = projectY(image.getOrigin().y());

      debugOutput("Cell array - START");
      pFile_      << "<g pointer-events=\"none\" stroke=\"none\" >\n";

#ifdef MAGICS_RASTER
if(!getExternal())
#endif
{
      const float x1 = projectX(image.getOrigin().x()+image.getWidth());
      const float y1 = projectY(image.getOrigin().y()+image.getHeight());
      const float dx = (x1-x0)/width;
      const float dy = (y1-y0)/height;

      for (int i=height-1;i>=0;i--)
      {
            for(int j=0;j<width; j++)
            {
              const int in = width*i+j;
              const short c = image[in];
 
              if(!(lt[c]=="undefined"))
              {
                  const int r = static_cast<int>(lt[c].red()*255.);
                  const int g = static_cast<int>(lt[c].green()*255.);
                  const int b = static_cast<int>(lt[c].blue()*255.);
                  const int wx = static_cast<int>( x0+(j*dx) );
                  const int wy = static_cast<int>( y0+(i*-dy) );
                  pFile_      << " <rect x=\""<<wx<<"\" y=\""<<setY(wy)<<"\" width=\""<<dx<<"\" height=\""<<dy<<"\""
                        << " fill=\"rgb("<< r << ","<< g << "," << b << ")\" />\n";
              }// point has colour
            }
      }
}
#ifdef MAGICS_RASTER
else
{
      stringstream out;
      out << "page"<<currentPage_<<"_"<<currentLayer_;

      string filename = tmp_pFile_+"_include_"+out.str()+".png";

      pFile_      << "<image x=\""<<x0<<"\" y=\""<<setY(y0)<<"\" "
            << " width=\""<<projectX(image.getWidth())<<"\" height=\""<<projectY(image.getHeight())<<"\" "
            << "xlink:href=\""<<filename<<"\" />\n";

      ColourTable &lt  = image.getColourTable(); 
      const int width  = image.getNumberOfColumns();
      const int height = image.getNumberOfRows();

      gdImagePtr im = gdImageCreateTrueColor(width,height);
      gdImageColorResolveAlpha(im, 255, 255, 255, 0);

      for (int i=height-1;i>=0;i--)
      {
            for(int j=0;j<width; j++)
            {
              const int in = width*i+j;    
              const short c = image[in];
              int col = 0;
//            if(!(lt[c]=="undefined"))
              {
                  const int r = static_cast<int>(lt[c].red()*255.);
                  const int g = static_cast<int>(lt[c].green()*255.);
                  const int b = static_cast<int>(lt[c].blue()*255.);

                  col = gdImageColorResolveAlpha(im,r,g,b,50);
              }// point has colour
//            else{
//                col = gdImageColorResolveAlpha(im,255,0,0,50);
//            }
              gdImageSetPixel(im, j, i, col);
            }
      }

      gdImageAlphaBlending(im, 1);
      gdImageSaveAlpha(im, 1); // save transparency

      svg_output_resource_list_.push_back(filename);

      FILE *outFile = fopen(filename.c_str(),"wb");
      gdImagePng(im,outFile);
      fclose(outFile);
      gdImageDestroy(im);
}
#endif
      pFile_      << "</g>\n";
      debugOutput("Cell array - END");
      return true;
}

/*!
  \brief Image render method for ALL drivers.

  This method should be used by all Magics++ drivers to render image objects.
*/
01201 MAGICS_NO_EXPORT void SVGDriver::renderImage(const ImportObject& obj) const
{
Log::dev()<< "SVG-IMAGEOBJECT: "<<obj.getFormat()<<" "<<obj.getPath()<<" "<< obj.getOrigin().x()<<" "<<obj.getOrigin().y()<< endl;
      closeGroup();
      std::string file = obj.getPath();

      string format = obj.getFormat();
      if(magCompare(format,"ps") || magCompare(format,"pdf"))
      {
            std::string cmd = "convert "+file+"[1] ___magics_svg_temp.png";
            Log::info() <<"SVGDriver::renderImage calling convert ... with: " <<cmd << endl;
            int status = system(cmd.c_str());
            if(status)
            {
                  Log::error() << "\nSVGDriver: Command exit not zero - NO PNG produced!\n"
                               << " COMMAND: "<<cmd<<"\n"<< endl;
                  return;
            }
            file="___magics_svg_temp.png";
      }

      if(!magCompare(format,"svg"))
      {
            const float x = projectX(obj.getOrigin().x());
            const float y = projectY(obj.getOrigin().y());
            const float h = projectY(obj.getOrigin().y()+obj.getHeight()) - y;
            pFile_ << "<image x=\""<<x<<"\" y=\""<<setY(y+h)
                   <<"\" width=\""  << projectX(obj.getOrigin().x()+obj.getWidth())  - x
                   <<"\" height=\"" << h
                   <<"\" xlink:href=\""<<file<<"\" />\n";
      }
      else
      {
            ifstream svgfile(file.c_str());
            if(!svgfile){
                  Log::error() << "SVGDriver::renderImage() --> Cannot open SVG file! " << file <<"!\n";
                  return;
            }
            char ch;
            while (svgfile.get(ch)){pFile_.put(ch);}
            svgfile.close();
            svg_output_resource_list_.push_back(file);
      }
}

/*!
  \brief prints debug output

  When Magics++ is compiled in debug mode these extra strings are printed.

  \note This can increase file and log file sizes if you run Magics++ in debug mode!

  \param s string to be printed
*/
01255 MAGICS_NO_EXPORT void SVGDriver::debugOutput(const string &s) const
{
      if(getDebug()) pFile_ << "<!-- "<<s<<" -->\n";
}

/*!
  \brief class information are given to the output-stream
*/
01263 void SVGDriver::print(ostream& out)  const
{
      out << "SVGDriver[";
      out << "]";
}

//! Method to plot symbols
/*!
 Needs special treatment of Logo. Much better quality when imported as GIF!
*/
01273 MAGICS_NO_EXPORT void SVGDriver::renderSymbols(const Symbol& symbol) const
{
      debugOutput("Symbols - START");

      closeGroup();
      if(symbol.getSymbol()=="logo_ecmwf")
      {
        if(inkscape_) pFile_ << "<g inkscape:groupmode=\"layer\" inkscape:label=\"ecmwf_logo\">\n";
        const string location = getLogoLocation();
        if(magCompare(location,"INLINE"))
            BaseDriver::renderSymbols(symbol);
        else
        {
            const float x = projectX(symbol[0].x());
            const float y = projectY(symbol[0].y());
            closeGroup();
            string logofile;
            if(magCompare(location,"WWW")) logofile = "http://www.ecmwf.int/publications/manuals/magics/magplus/resources/ecmwf_logo.png";
            else if(magCompare(location,"LOCAL")) logofile = "ecmwf_logo.png";
            else logofile = getEnvVariable("MAGPLUS_HOME") + MAGPLUS_PATH_TO_SHARE_ + "ecmwf_logo.png";
svg_output_resource_list_.push_back(logofile);
            pFile_ << "<a xlink:href=\"http://www.ecmwf.int\">"
                   << "<image x=\""<<x-(y*1.35)<<"\" y=\""<<setY(y+(y*.5))<<"\" width=\""<<y*5.4<<"\" height=\""<<y<<"\" xlink:href=\""<<logofile<<"\" />"
                   << "</a>\n";
        }
        if(inkscape_) pFile_ << "</g>\n";
      }
      else 
            BaseDriver::renderSymbols(symbol);

      debugOutput("Symbols - END");
}

static SimpleObjectMaker<SVGDriver, BaseDriver> SVG_driver("SVG");

Generated by  Doxygen 1.6.0   Back to index