bpp-core  2.1.0
PgfGraphicDevice.cpp
Go to the documentation of this file.
00001 //
00002 // File: PgfGraphicDevice.cpp
00003 // Created by: Julien Dutheil
00004 // Created on: Thu Jun 19 2008
00005 //
00006 
00007 /*
00008 Copyright or © or Copr. CNRS, (November 17, 2004)
00009 
00010 This software is a computer program whose purpose is to provide utilitary
00011 classes. This file belongs to the Bio++ Project.
00012 
00013 This software is governed by the CeCILL  license under French law and
00014 abiding by the rules of distribution of free software.  You can  use, 
00015 modify and/ or redistribute the software under the terms of the CeCILL
00016 license as circulated by CEA, CNRS and INRIA at the following URL
00017 "http://www.cecill.info". 
00018 
00019 As a counterpart to the access to the source code and  rights to copy,
00020 modify and redistribute granted by the license, users are provided only
00021 with a limited warranty  and the software's author,  the holder of the
00022 economic rights,  and the successive licensors  have only  limited
00023 liability. 
00024 
00025 In this respect, the user's attention is drawn to the risks associated
00026 with loading,  using,  modifying and/or developing or reproducing the
00027 software by the user in light of its specific status of free software,
00028 that may mean  that it is complicated to manipulate,  and  that  also
00029 therefore means  that it is reserved for developers  and  experienced
00030 professionals having in-depth computer knowledge. Users are therefore
00031 encouraged to load and test the software's suitability as regards their
00032 requirements in conditions enabling the security of their systems and/or 
00033 data to be ensured and,  more generally, to use and operate it in the 
00034 same conditions as regards security. 
00035 
00036 The fact that you are presently reading this means that you have had
00037 knowledge of the CeCILL license and that you accept its terms.
00038 */
00039 
00040 #include "PgfGraphicDevice.h"
00041 using namespace bpp;
00042 
00043 #include<algorithm>
00044 using namespace std;
00045 
00046 
00047 PgfGraphicDevice::PgfGraphicDevice(std::ostream& out, double unit) :
00048   out_(out),
00049   fgColorStr_("black"),
00050   bgColorStr_("white"),
00051   content_(),
00052   layers_(),
00053   colorIndex_(),
00054   colorCount_(0),
00055   useLayers_(false),
00056   contentStarted_(false),
00057   fontShapes_(),
00058   fontSeries_()
00059 {
00060   colorIndex_[ColorTools::BLACK]   = "black";
00061   colorIndex_[ColorTools::WHITE]   = "white";
00062   colorIndex_[ColorTools::BLUE]    = "blue";
00063   colorIndex_[ColorTools::RED]     = "red";
00064   colorIndex_[ColorTools::GREEN]   = "green";
00065   colorIndex_[ColorTools::YELLOW]  = "yellow";
00066   colorIndex_[ColorTools::CYAN]    = "cyan";
00067   colorIndex_[ColorTools::MAGENTA] = "magenta";
00068 
00069   fontShapes_[Font::STYLE_NORMAL]  = "n";
00070   fontShapes_[Font::STYLE_ITALIC]  = "it";
00071   fontSeries_[Font::WEIGHT_NORMAL] = "m";
00072   fontSeries_[Font::WEIGHT_BOLD]   = "bx";
00073 
00074   setCurrentFont(Font("cmtt", Font::STYLE_NORMAL, Font::WEIGHT_NORMAL, 12));
00075   setXUnit(unit);
00076   setYUnit(unit);
00077 }
00078 
00079 void PgfGraphicDevice::begin()
00080 {
00081   content_.clear();
00082   layers_.clear();
00083   colorIndex_.clear();
00084   colorCount_ = 0;
00085   useLayers_ = false;
00086   contentStarted_ = false;
00087 }
00088 
00089 bool comp( int a, int b ) { return a > b; } ;
00090 void PgfGraphicDevice::end()
00091 {
00092   ostringstream oss;
00093   if (useLayers_)
00094     oss << "\\end{pgfonlayer}{" << TextTools::toString(getCurrentLayer()) << "}" << endl;
00095   content_.push_back(oss.str());
00096 
00097   //Header:
00098   out_ << "\\documentclass{article}" << endl;
00099   out_ << "% This figure was generated by the Bio++ Pgf Graphic Device." << endl;
00100   out_ << "% Althought this file can be compiled 'as is' it may not be displayed correctly, depending on the size of the picture." << endl;
00101   out_ << "% You may consider copying the pgfpicture environment to your own LaTeX file and play with pgf settings (e.g. the pgfpages module)." << endl;
00102   out_ << "% You can also use the geometry package, for instance:" << endl;
00103   out_ << "% \\usepackage[a3paper]{geometry}" << endl;
00104   out_ << "\\usepackage{pgf}" << endl;
00105   for(map<const RGBColor, string>::iterator it = colorIndex_.begin(); it != colorIndex_.end(); it++)
00106   {
00107     if(it->second.substr(0,3) == "use")
00108       out_ << "\\definecolor{" << it->second << "}{rgb}{" << it->first[0]/255. << "," << it->first[1]/255. << "," << it->first[2]/255. << "}" << endl;    
00109   }
00110   out_ << "\\begin{document}" << endl;
00111 
00112   //Declare and set layers:
00113   if (useLayers_)
00114   {
00115     string tmp;
00116     sort(layers_.begin(), layers_.end(), comp);
00117     for(unsigned int i = 0; i < layers_.size(); i++)
00118     {
00119       if(i > 0) tmp += ",";
00120       tmp += TextTools::toString(layers_[i]);
00121       out_ << "\\pgfdeclarelayer{" << layers_[i] << "}" << endl;
00122     }
00123     out_ << "\\pgfsetlayers{" << tmp << "}" << endl;
00124   }
00125 
00126   //Start picture:
00127   out_ << "\\begin{pgfpicture}" << endl;
00128   out_ << "\\pgfsetxvec{\\pgfpoint{" << getXUnit() << "cm}{0cm}}" << endl;
00129   out_ << "\\pgfsetyvec{\\pgfpoint{0cm}{-" << getYUnit() << "cm}}" << endl;
00130   
00131   for(unsigned int i = 0; i < content_.size(); i++)
00132   {
00133     out_ << content_[i] << endl;
00134   }
00135   
00136   out_ << "\\end{pgfpicture}" << endl;
00137   out_ << "\\end{document}" << endl;
00138 }
00139 
00140 void PgfGraphicDevice::setCurrentForegroundColor(const RGBColor& color)
00141 {
00142   map<const RGBColor, string>::iterator it = colorIndex_.find(color);
00143   if(it != colorIndex_.end())
00144   {
00145     fgColorStr_ = it->second;
00146   }
00147   else
00148   {
00149     colorCount_++;
00150     fgColorStr_ = "usercolor" + TextTools::toString(colorCount_);
00151     colorIndex_[color] = fgColorStr_;
00152   }
00153   AbstractGraphicDevice::setCurrentForegroundColor(color);
00154   ostringstream oss;
00155   oss << "\\pgfsetstrokecolor{" << fgColorStr_ << "}" << endl;
00156   content_.push_back(oss.str());
00157 }
00158 
00159 void PgfGraphicDevice::setCurrentBackgroundColor(const RGBColor& color)
00160 {
00161   map<const RGBColor, string>::iterator it = colorIndex_.find(color);
00162   if (it != colorIndex_.end())
00163   {
00164     bgColorStr_ = it->second;
00165   }
00166   else
00167   {
00168     colorCount_++;
00169     bgColorStr_ = "usercolor" + TextTools::toString(colorCount_);
00170     colorIndex_[color] = bgColorStr_;
00171   }
00172   AbstractGraphicDevice::setCurrentBackgroundColor(color);
00173   ostringstream oss;
00174   oss << "\\pgfsetfillcolor{" << bgColorStr_ << "}" << endl;
00175   content_.push_back(oss.str());
00176 }
00177 
00178 void PgfGraphicDevice::setCurrentFont(const Font& font)
00179 {
00180   AbstractGraphicDevice::setCurrentFont(font);
00181   ostringstream oss;
00182   oss << "\\fontfamily{" << font.getFamily() << "}" << endl;
00183   oss << "\\fontseries{" << fontSeries_[font.getSeries()] << "}" << endl;
00184   oss << "\\fontshape{"  << fontShapes_[font.getShape()] << "}"  << endl;
00185   oss << "\\fontsize{"   << font.getSize() << "}{" << font.getSize() << "}" << endl;
00186   oss << "\\selectfont"  << endl;
00187   content_.push_back(oss.str());
00188 }
00189 
00190 void PgfGraphicDevice::setCurrentPointSize(unsigned int size)
00191 {
00192   AbstractGraphicDevice::setCurrentPointSize(size);
00193   ostringstream oss;
00194   oss << "\\pgfsetlinewidth{" << x_(size) << "}" << endl;
00195   content_.push_back(oss.str());
00196 }
00197 
00198 void PgfGraphicDevice::setCurrentLineType(short type) throw (Exception)
00199 { 
00200   AbstractGraphicDevice::setCurrentLineType(type);
00201   if(type == LINE_SOLID)
00202   {
00203     ostringstream oss;
00204     oss << "\\pgfsetdash{}{0pt}" << endl;
00205     content_.push_back(oss.str());
00206   }
00207   else if(type == LINE_DASHED)
00208   {
00209     ostringstream oss;
00210     oss << "\\pgfsetdash{{3mm}{2mm}}{0pt}" << endl;
00211     content_.push_back(oss.str());
00212   }
00213   else if(type == LINE_DOTTED)
00214   {
00215     ostringstream oss;
00216     oss << "\\pgfsetdash{{" << (x_(getCurrentPointSize())) << "}{" << (x_(getCurrentPointSize())) << "}}{0pt}" << endl;
00217     content_.push_back(oss.str());
00218   }
00219   else throw Exception("PgfGraphicDevice::setCurrentLineType. Unknown line type: " + TextTools::toString(type));
00220 }
00221 
00222 void PgfGraphicDevice::setCurrentLayer(int layerIndex)
00223 {
00224   if (!useLayers_ && contentStarted_)
00225     throw Exception("PgfGraphicDevice::setCurrentLayer. A layer is specified after some content has been already added, this would result in a corrupted display.");
00226   ostringstream oss;
00227   if (useLayers_)
00228     oss << "\\end{pgfonlayer}{" << TextTools::toString(getCurrentLayer()) << "}" << endl;
00229   oss << "\\begin{pgfonlayer}{" << TextTools::toString(layerIndex) << "}" << endl;
00230   //We have to recall the current color values for this layer:
00231   oss << "\\pgfsetstrokecolor{" << fgColorStr_ << "}" << endl;
00232   oss << "\\pgfsetfillcolor{" << bgColorStr_ << "}" << endl;
00233   content_.push_back(oss.str());
00234   AbstractGraphicDevice::setCurrentLayer(layerIndex);
00235   if (find(layers_.begin(), layers_.end(), layerIndex) == layers_.end())
00236     layers_.push_back(layerIndex);
00237   useLayers_ = true;
00238 }
00239 
00240 void PgfGraphicDevice::drawLine(double x1, double y1, double x2, double y2)
00241 {
00242   ostringstream oss;
00243   oss << "\\pgfpathmoveto{\\pgfpointxy{" << x1 << "}{" << y1 << "}}" << endl;
00244   oss << "\\pgfpathlineto{\\pgfpointxy{" << x2 << "}{" << y2 << "}}" << endl;
00245   oss << "\\pgfpathclose" << endl;
00246   oss << "\\pgfusepath{stroke}" << endl;
00247   content_.push_back(oss.str());
00248   contentStarted_ = true;
00249 }
00250  
00251 void PgfGraphicDevice::drawRect(double x, double y, double width, double height, short fill)
00252 {
00253   ostringstream oss;
00254   oss << "\\pgfpathrectangle{\\pgfpointxy{" << x << "}{" << y << "}}{\\pgfpointxy{" << width << "}{" << height << "}}" << endl;
00255   if(fill == FILL_FILLED)
00256     oss << "\\pgfusepath{stroke,fill}" << endl;
00257   else
00258     oss << "\\pgfusepath{stroke}" << endl;
00259   content_.push_back(oss.str());
00260   contentStarted_ = true;
00261 }
00262 
00263 void PgfGraphicDevice::drawCircle(double x, double y, double radius, short fill)
00264 {
00265   ostringstream oss;
00266   oss << "\\pgfpathcircle{\\pgfpointxy{" << x << "}{" << y << "}}{" << radius << "}" << endl;
00267   if(fill == FILL_FILLED)
00268     oss << "\\pgfusepath{stroke,fill}" << endl;
00269   else
00270     oss << "\\pgfusepath{stroke}" << endl;
00271   content_.push_back(oss.str());
00272   contentStarted_ = true;
00273 }
00274 
00275 void PgfGraphicDevice::drawText(double x, double y, const std::string& text, short hpos, short vpos, double angle) throw (UnvalidFlagException)
00276 {
00277   string anchor;
00278   if(vpos == TEXT_VERTICAL_BOTTOM)
00279     anchor = "bottom";
00280   else if(vpos == TEXT_VERTICAL_TOP)
00281     anchor = "top";
00282   else if(vpos == TEXT_VERTICAL_CENTER)
00283     anchor = "base";
00284   else throw UnvalidFlagException("PgfGraphicDevice::drawText. Invalid vertical alignment option.");
00285   if(hpos == TEXT_HORIZONTAL_LEFT)
00286     anchor += ",left";
00287   else if(hpos == TEXT_HORIZONTAL_RIGHT)
00288     anchor += ",right";
00289   else if(hpos == TEXT_HORIZONTAL_CENTER)
00290     anchor += "";
00291   else throw UnvalidFlagException("PgfGraphicDevice::drawText. Invalid horizontal alignment option.");
00292 
00293   ostringstream oss;
00294   oss << "\\pgftransformrotate{" << angle << "}" << endl;
00295   oss << "\\pgftext[" << anchor << ",at=\\pgfpointxy{" << x << "}{" << y << "}]{\\textcolor{" << fgColorStr_ << "}" << text << "}" << endl;
00296   content_.push_back(oss.str());
00297   contentStarted_ = true;
00298 }
00299 
 All Classes Namespaces Files Functions Variables Typedefs Friends