svg.cc

Go to the documentation of this file.
00001 /*                            Package   : libhex
00002  * svg.cc                     Created   : 2007/10/25
00003  *                            Author    : Alex Tingle
00004  *
00005  *    Copyright (C) 2007-2008, Alex Tingle.
00006  *
00007  *    This file is part of the libhex application.
00008  *
00009  *    libhex is free software; you can redistribute it and/or
00010  *    modify it under the terms of the GNU Lesser General Public
00011  *    License as published by the Free Software Foundation; either
00012  *    version 2.1 of the License, or (at your option) any later version.
00013  *
00014  *    libhex is distributed in the hope that it will be useful,
00015  *    but WITHOUT ANY WARRANTY; without even the implied warranty of
00016  *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00017  *    Lesser General Public License for more details.
00018  *
00019  *    You should have received a copy of the GNU Lesser General Public
00020  *    License along with this library; if not, write to the Free Software
00021  *    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
00022  */
00023 
00024 #include "hexsvg.h"
00025 
00026 #include <cassert>
00027 #include <fstream>
00028 #include <sstream>
00029 
00030 
00031 namespace hex {
00032 namespace svg {
00033 
00034 
00036 std::string
00037 strip(const std::string& s)
00038 {
00039   std::string::size_type p0 =s.find_first_not_of(" \t\n");
00040   std::string::size_type p1 =s.find_last_of(" \t\n");
00041   return s.substr(p0,p1-p0);
00042 }
00043 
00044 
00045 std::string
00046 style_str(const Style& st)
00047 {
00048   std::string result ="";
00049   for(Style::const_iterator it=st.begin(); it!=st.end(); ++it)
00050   {
00051     if(!result.empty())
00052         result += ';';
00053     result += it->first + ":" + it->second;
00054   }
00055   return result;
00056 }
00057 
00058 
00059 Style
00060 style_dict(const std::string& s) throw(hex::invalid_argument)
00061 {
00062   Style result;
00063   std::string::size_type pos =0;
00064   while(true)
00065   {
00066     pos=s.find_first_not_of(";",pos);
00067     if(pos==std::string::npos)
00068         break;
00069     std::string::size_type semi =s.find(";",pos);
00070     std::string clause =s.substr(pos,semi-pos);
00071     std::string::size_type colon =clause.find(":");
00072     if(colon==std::string::npos || colon==0 || (colon+1)>=clause.size())
00073         throw hex::invalid_argument(s);
00074     result[ strip(s.substr(0,colon)) ] = strip(s.substr(colon+1));
00075     pos=semi;
00076   }
00077   return result;
00078 }
00079 
00080 
00087 std::string
00088 path_append(char& cmd, Point& p, char cmd1, const Point& p1)
00089 {
00090   std::ostringstream ss;
00091   if(p != p1)
00092   {
00093     if(cmd != cmd1)
00094     {
00095       ss<<" "<<cmd1;
00096       cmd=cmd1;
00097     }
00098     ss<<" "<<(p1-p);
00099     p=p1;
00100   }
00101   return ss.str();
00102 }
00103 
00104 
00106 template<class InputIterator>
00107 std::ostream&
00108 output_path_data(
00109     const Document&  doc,
00110     std::ostream&    os,
00111     InputIterator    first,
00112     InputIterator    last
00113   )
00114 {
00115   assert(first!=last);
00116   --last;
00117   os<<"M "<<doc.T(*first)<<" L";
00118   for(InputIterator p =++first; p!=last; ++p)
00119       os<<" "<<doc.T(*p);
00120   os<<" Z";
00121   return os;
00122 }
00123 
00124 
00125 //
00126 // Identity
00127 
00128 std::string
00129 Identity::attributes(void) const
00130 {
00131   std::string result ="";
00132   if(!this->id.empty())
00133       result += std::string(" id=\"") + this->id + "\"";
00134   if(!this->style.empty())
00135       result += std::string(" style=\"") + this->style + "\"";
00136   if(!this->className.empty())
00137       result += std::string(" class=\"") + this->className + "\"";
00138   return result;
00139 }
00140 
00141 
00142 //
00143 // Document
00144 
00145 Point
00146 Document::T(const Point& p) const
00147 {
00148   return Point( p.x - p0.x, p1.y - p.y );
00149 }
00150 
00151 
00152 std::string
00153 Document::header() const
00154 {
00155   std::ostringstream os;
00156   os<<
00157     "<?xml version=\"1.0\" standalone=\"no\"?>\n"
00158     "<!DOCTYPE svg PUBLIC \"-//W3C//DTD SVG 1.1//EN\" "
00159       "\"http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd\">\n";
00160 #if defined(HEX_EXTERNAL_CSS) && HEX_EXTERNAL_CSS!=0
00161   for(std::list<std::string>::const_iterator s =this->stylesheets.begin();
00162                                              s!=this->stylesheets.end();
00163                                            ++s)
00164   {
00165     os<<"<?xml-stylesheet href=\""<<(*s)<<"\" type=\"text/css\"?>\n";
00166   }
00167 #endif
00168   Point extent =p1-p0;
00169   os<<
00170     "<svg width=\"100%\" height=\"100%\" viewBox=\""
00171     << 0L <<" "<< 0L << " " << extent.x <<" "<< extent.y <<
00172     "\" version=\"1.1\""
00173       " xmlns=\"http://www.w3.org/2000/svg\""
00174       " xmlns:xlink=\"http://www.w3.org/1999/xlink\">\n"
00175 
00176     "<defs>\n";
00177 #if !defined(HEX_EXTERNAL_CSS) || HEX_EXTERNAL_CSS==0
00178   if(!this->stylesheets.empty())
00179   {
00180     os<<"<style type=\"text/css\"><![CDATA[\n";
00181     for(std::list<std::string>::const_iterator s =this->stylesheets.begin();
00182                                                s!=this->stylesheets.end();
00183                                              ++s)
00184     {
00185       std::ifstream css(s->c_str());
00186 
00187       // Copy the css file to os.
00188       if(css)
00189       {
00190         char buf[1024];
00191         std::streamsize total =0;
00192         while(css.good())
00193         {
00194           std::streamsize bytes =css.readsome(buf,sizeof(buf));
00195           if(!bytes)
00196             break;
00197           total+=bytes;
00198           os.write(buf,bytes);
00199         }
00200       }
00201     }
00202     os<<"]]></style>\n";
00203   }
00204 #endif
00205   os<<
00206     "<marker id=\"Triangle\""
00207     " viewBox=\"0 0 10 10\" refX=\"0\" refY=\"5\" "
00208     " markerUnits=\"strokeWidth\""
00209     " markerWidth=\"4\" markerHeight=\"3\""
00210     " orient=\"auto\">\n"
00211     "<path d=\"M 0 0 L 10 5 L 0 10 z\" />\n"
00212     "</marker>\n";
00213   for(std::list<std::string>::const_iterator d =this->defs.begin();
00214                                              d!=this->defs.end();
00215                                            ++d)
00216   {
00217     os<<(*d)<<"\n";
00218   }
00219   os<<"</defs>\n";
00220   return os.str();
00221 }
00222 
00223 
00224 std::string
00225 Document::footer(void) const
00226 {
00227   return "</svg>\n";
00228 }
00229 
00230 
00231 //
00232 // Draw functions
00233 
00234 std::string
00235 Document::draw_simple_area(const Area& a, float bias)
00236 {
00237   return draw_poly(a.boundary().stroke(bias),true,&a);
00238 }
00239 
00240 
00241 std::string
00242 Document::draw_complex_area(const Area& a, float bias)
00243 {
00244   using namespace std;
00245   std::ostringstream os;
00246   os<<"<path fill-rule=\"nonzero\""<<a.attributes()<<" d=\"";
00247   const std::list<Point> apoints =a.boundary().stroke(bias);
00248   output_path_data(*this,os,apoints.begin(),apoints.end());
00249   std::list<Area> voids =a.enclosed_areas();
00250   for(list<Area>::const_iterator v=voids.begin(); v!=voids.end(); ++v)
00251   {
00252     os<<" ";
00253     const std::list<Point> vpoints =v->boundary().stroke(-bias);
00254     output_path_data(*this,os,vpoints.rbegin(),vpoints.rend());
00255   }
00256   os<<"\"/>\n";
00257   return os.str();
00258 }
00259 
00260 
00261 std::string
00262 Document::draw_skeleton(const Area& a, bool include_boundary)
00263 {
00264   std::ostringstream os;
00265   os<<"<path"<<a.attributes()<<" d=\"";
00266   const std::list<Boundary> bb =a.skeleton(include_boundary);
00267   Point curr =T( bb.front().edges().front()->start_point() );
00268   os<<"M "<<curr;
00269   char cmd ='\0';
00270   for(std::list<Boundary>::const_iterator b=bb.begin(); b!=bb.end(); ++b)
00271   {
00272     const std::list<Edge*> edges =b->edges();
00273     assert(!edges.empty());
00274     os<<path_append(cmd,curr,'m',T( edges.front()->start_point() ));
00275     for(std::list<Edge*>::const_iterator e=edges.begin(); e!=edges.end(); ++e)
00276     {
00277       os<<path_append(cmd,curr,'l',T( (**e).end_point() ));
00278     }
00279   }
00280   os<<"\"/>\n";
00281   return os.str();
00282 }
00283 
00284 
00285 std::string
00286 Document::draw_boundary(const Boundary& b, float bias)
00287 {
00288   return draw_poly(b.stroke(bias), b.is_closed(), &b);
00289 }
00290 
00291 
00292 std::string
00293 Document::draw_path(const Path& p)
00294 {
00295   std::ostringstream os;
00296   const std::list<Hex*>& hexes =p.hexes();
00297   assert(!hexes.empty());
00298   if(hexes.size()>1) // Nothing to draw if there is only one hex in the path.
00299   {
00300     std::list<Point> points;
00301     for(std::list<Hex*>::const_iterator h =hexes.begin(); h!=hexes.end(); ++h)
00302         points.push_back( (**h).centre() );
00303     bool is_closed =( hexes.front()==hexes.back() );
00304     os<<draw_poly(points,is_closed,&p);
00305   }
00306   return os.str();
00307 }
00308 
00309 
00310 std::string
00311 Document::draw_poly(
00312     std::list<Point>  points,
00313     bool              closed,
00314     const Identity*   identity
00315   )
00316 {
00317   assert(!points.empty());
00318   std::ostringstream os;
00319   if(closed)
00320       points.pop_back();
00321   if(closed)
00322       os<<"<polygon";
00323   else
00324       os<<"<polyline";
00325   if(identity)
00326       os<<identity->attributes();
00327   os<<" points=\"";
00328   for(std::list<Point>::const_iterator p=points.begin(); p!=points.end(); ++p)
00329   {
00330     if(p!=points.begin())
00331        os<<" ";
00332     os<<T(*p);
00333   }
00334   os<<"\"/>\n";
00335   return os.str();
00336 }
00337 
00338 
00339 // Construction
00340 
00341 Document::Document(const Grid& grid)
00342   : _grid(grid),
00343     p0(0.0,0.0),
00344     p1(grid.width(),grid.height()), 
00345     stylesheets(),
00346     defs()
00347 {}
00348 
00349 
00350 } // end namespace svg
00351 } // end namespace hex

Generated on Thu Feb 21 00:00:54 2008 for libhex by  doxygen 1.5.1