$extrastylesheet
postscript_io.C
Go to the documentation of this file.
00001 // The libMesh Finite Element Library.
00002 // Copyright (C) 2002-2014 Benjamin S. Kirk, John W. Peterson, Roy H. Stogner
00003 
00004 // This library is free software; you can redistribute it and/or
00005 // modify it under the terms of the GNU Lesser General Public
00006 // License as published by the Free Software Foundation; either
00007 // version 2.1 of the License, or (at your option) any later version.
00008 
00009 // This library is distributed in the hope that it will be useful,
00010 // but WITHOUT ANY WARRANTY; without even the implied warranty of
00011 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00012 // Lesser General Public License for more details.
00013 
00014 // You should have received a copy of the GNU Lesser General Public
00015 // License along with this library; if not, write to the Free Software
00016 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
00017 
00018 // C++ includes
00019 #include <ctime>
00020 #include <iomanip>
00021 #include <iostream>
00022 #include <sstream>
00023 
00024 // Local includes
00025 #include "libmesh/postscript_io.h"
00026 #include "libmesh/mesh_tools.h"
00027 #include "libmesh/elem.h"
00028 
00029 namespace libMesh
00030 {
00031 
00032 
00033 // Transformation map between monomial (physical space) and Bezier bases.
00034 const float PostscriptIO::_bezier_transform[3][3] =
00035   {
00036     {-1.f/6.f, 1.f/6.f, 1.},
00037     {-1.f/6.f, 0.5,     1.f/6.f},
00038     {0.,       1.,      0.}
00039   };
00040 
00041 
00042 PostscriptIO::PostscriptIO (const MeshBase& mesh_in)
00043   : MeshOutput<MeshBase> (mesh_in),
00044     shade_value(0.0),
00045     line_width(0.5),
00046     //_M(3,3),
00047     _offset(0., 0.),
00048     _scale(1.0),
00049     _current_point(0., 0.)
00050 {
00051   // This code is still undergoing some development.
00052   libmesh_experimental();
00053 
00054   // Entries of transformation matrix from physical to Bezier coords.
00055   // _M(0,0) = -1./6.;    _M(0,1) = 1./6.;    _M(0,2) = 1.;
00056   // _M(1,0) = -1./6.;    _M(1,1) = 0.5  ;    _M(1,2) = 1./6.;
00057   // _M(2,0) = 0.    ;    _M(2,1) = 1.   ;    _M(2,2) = 0.;
00058 
00059   // Make sure there is enough room to store Bezier coefficients.
00060   _bezier_coeffs.resize(3);
00061 }
00062 
00063 
00064 
00065 PostscriptIO::~PostscriptIO ()
00066 {
00067 }
00068 
00069 
00070 
00071 void PostscriptIO::write (const std::string& fname)
00072 {
00073   // We may need to gather a ParallelMesh to output it, making that
00074   // const qualifier in our constructor a dirty lie
00075   MeshSerializer serialize(const_cast<MeshBase&>(this->mesh()), !_is_parallel_format);
00076 
00077   if (this->mesh().processor_id() == 0)
00078     {
00079       // Get a constant reference to the mesh.
00080       const MeshBase& the_mesh = MeshOutput<MeshBase>::mesh();
00081 
00082       // Only works in 2D
00083       libmesh_assert_equal_to (the_mesh.mesh_dimension(), 2);
00084 
00085       // Create output file stream.
00086       // _out is now a private member of the class.
00087       _out.open(fname.c_str());
00088 
00089       // Make sure it opened correctly
00090       if (!_out.good())
00091         libmesh_file_error(fname.c_str());
00092 
00093       // The mesh bounding box gives us info about what the
00094       // Postscript bounding box should be.
00095       MeshTools::BoundingBox bbox = MeshTools::bounding_box(the_mesh);
00096 
00097       // Add a little extra padding to the "true" bounding box so
00098       // that we can still see the boundary
00099       const Real percent_padding = 0.01;
00100       const Real dx=bbox.second(0)-bbox.first(0); libmesh_assert_greater (dx, 0.0);
00101       const Real dy=bbox.second(1)-bbox.first(1); libmesh_assert_greater (dy, 0.0);
00102 
00103       const Real x_min = bbox.first(0)  - percent_padding*dx;
00104       const Real y_min = bbox.first(1)  - percent_padding*dy;
00105       const Real x_max = bbox.second(0) + percent_padding*dx;
00106       const Real y_max = bbox.second(1) + percent_padding*dy;
00107 
00108       // Width of the output as given in postscript units.
00109       // This usually is given by the strange unit 1/72 inch.
00110       // A width of 300 represents a size of roughly 10 cm.
00111       const Real width = 300;
00112       _scale = width / (x_max-x_min);
00113       _offset(0) = x_min;
00114       _offset(1) = y_min;
00115 
00116       // Header writing stuff stolen from Deal.II
00117       std::time_t  time1= std::time (0);
00118       std::tm     *time = std::localtime(&time1);
00119       _out << "%!PS-Adobe-2.0 EPSF-1.2" << '\n'
00120         //<< "%!PS-Adobe-1.0" << '\n' // Lars' PS version
00121            << "%%Filename: " << fname << '\n'
00122            << "%%Title: LibMesh Output" << '\n'
00123            << "%%Creator: LibMesh: A C++ finite element library" << '\n'
00124            << "%%Creation Date: "
00125            << time->tm_year+1900 << "/"
00126            << time->tm_mon+1 << "/"
00127            << time->tm_mday << " - "
00128            << time->tm_hour << ":"
00129            << std::setw(2) << time->tm_min << ":"
00130            << std::setw(2) << time->tm_sec << '\n'
00131            << "%%BoundingBox: "
00132         // lower left corner
00133            << "0 0 "
00134         // upper right corner
00135            << static_cast<unsigned int>( rint((x_max-x_min) * _scale ))
00136            << ' '
00137            << static_cast<unsigned int>( rint((y_max-y_min) * _scale ))
00138            << '\n';
00139 
00140       // define some abbreviations to keep
00141       // the output small:
00142       // m=move turtle to
00143       // l=define a line
00144       // s=set rgb color
00145       // sg=set gray value
00146       // lx=close the line and plot the line
00147       // lf=close the line and fill the interior
00148       _out << "/m {moveto} bind def"      << '\n'
00149            << "/l {lineto} bind def"      << '\n'
00150            << "/s {setrgbcolor} bind def" << '\n'
00151            << "/sg {setgray} bind def"    << '\n'
00152            << "/cs {curveto stroke} bind def" << '\n'
00153            << "/lx {lineto closepath stroke} bind def" << '\n'
00154            << "/lf {lineto closepath fill} bind def"   << '\n';
00155 
00156       _out << "%%EndProlog" << '\n';
00157       //  << '\n';
00158 
00159       // Set line width in the postscript file.
00160       _out << line_width << " setlinewidth" << '\n';
00161 
00162       // Set line cap and join options
00163       _out << "1 setlinecap" << '\n';
00164       _out << "1 setlinejoin" << '\n';
00165 
00166       // allow only five digits for output (instead of the default
00167       // six); this should suffice even for fine grids, but reduces
00168       // the file size significantly
00169       _out << std::setprecision (5);
00170 
00171       // Loop over the active elements, draw lines for the edges.  We
00172       // draw even quadratic elements with straight sides, i.e. a straight
00173       // line sits between each pair of vertices.  Also we draw every edge
00174       // for an element regardless of the fact that it may overlap with
00175       // another.  This would probably be a useful optimization...
00176       MeshBase::const_element_iterator       el     = the_mesh.active_elements_begin();
00177       const MeshBase::const_element_iterator end_el = the_mesh.active_elements_end();
00178       for ( ; el != end_el; ++el)
00179         {
00180           //const Elem* elem = *el;
00181 
00182           this->plot_linear_elem(*el);
00183           //this->plot_quadratic_elem(*el); // Experimental
00184         }
00185 
00186       // Issue the showpage command, and we're done.
00187       _out << "showpage" << std::endl;
00188 
00189     } // end if (this->mesh().processor_id() == 0)
00190 }
00191 
00192 
00193 
00194 
00195 
00196 
00197 void PostscriptIO::plot_linear_elem(const Elem* elem)
00198 {
00199   // Clear the string contents.  Yes, this really is how you do that...
00200   _cell_string.str("");
00201 
00202   // The general strategy is:
00203   // 1.) Use m  := {moveto} to go to vertex 0.
00204   // 2.) Use l  := {lineto} commands to draw lines to vertex 1, 2, ... N-1.
00205   // 3a.) Use lx := {lineto closepath stroke} command at  vertex N to draw the last line.
00206   // 3b.)     lf := {lineto closepath fill} command to shade the cell just drawn
00207   // All of our 2D elements' vertices are numbered in counterclockwise order,
00208   // so we can just draw them in the same order.
00209 
00210   // 1.)
00211   _current_point = (elem->point(0) - _offset) * _scale;
00212   _cell_string << _current_point(0) << " " << _current_point(1) << " "; // write x y
00213   _cell_string << "m ";
00214 
00215   // 2.)
00216   const unsigned int nv=elem->n_vertices();
00217   for (unsigned int v=1; v<nv-1; ++v)
00218     {
00219       _current_point = (elem->point(v) - _offset) * _scale;
00220       _cell_string << _current_point(0) << " " << _current_point(1) << " "; // write x y
00221       _cell_string << "l ";
00222     }
00223 
00224   // 3.)
00225   _current_point = (elem->point(nv-1) - _offset) * _scale;
00226   _cell_string << _current_point(0) << " " << _current_point(1) << " "; // write x y
00227 
00228   // We draw the shaded (interior) parts first, if applicable.
00229   if (shade_value > 0.0)
00230     _out << shade_value << " sg " << _cell_string.str() << "lf\n";
00231 
00232   // Draw the black lines (I guess we will always do this)
00233   _out << "0 sg " << _cell_string.str() << "lx\n";
00234 }
00235 
00236 
00237 
00238 
00239 void PostscriptIO::plot_quadratic_elem(const Elem* elem)
00240 {
00241   for (unsigned int ns=0; ns<elem->n_sides(); ++ns)
00242     {
00243       // Build the quadratic side
00244       UniquePtr<Elem> side = elem->build_side(ns);
00245 
00246       // Be sure it's quadratic (Edge2).  Eventually we could
00247       // handle cubic elements as well...
00248       libmesh_assert_equal_to ( side->type(), EDGE3 );
00249 
00250       _out << "0 sg ";
00251 
00252       // Move to the first point on this side.
00253       _current_point = (side->point(0) - _offset) * _scale;
00254       _out << _current_point(0) << " " << _current_point(1) << " "; // write x y
00255       _out << "m ";
00256 
00257       // Compute _bezier_coeffs for this edge.  This fills up
00258       // the _bezier_coeffs vector.
00259       this->_compute_edge_bezier_coeffs(side.get());
00260 
00261       // Print curveto path to file
00262       for (unsigned int i=0; i<_bezier_coeffs.size(); ++i)
00263         _out << _bezier_coeffs[i](0) << " " << _bezier_coeffs[i](1) << " ";
00264       _out << " cs\n";
00265     }
00266 }
00267 
00268 
00269 
00270 
00271 void PostscriptIO::_compute_edge_bezier_coeffs(const Elem* elem)
00272 {
00273   // I only know how to do this for an Edge3!
00274   libmesh_assert_equal_to (elem->type(), EDGE3);
00275 
00276   // Get x-coordinates into an array, transform them,
00277   // and repeat for y.
00278   float
00279     phys_coords[3] = {0., 0., 0.},
00280     bez_coords[3]  = {0., 0., 0.};
00281 
00282     for (unsigned int i=0; i<2; ++i)
00283       {
00284         // Initialize vectors.  Physical coordinates are initialized
00285         // by their postscript-scaled values.
00286         for (unsigned int j=0; j<3; ++j)
00287           {
00288             phys_coords[j] = static_cast<float>
00289               ((elem->point(j)(i) - _offset(i)) * _scale);
00290             bez_coords[j] = 0.; // zero out result vector
00291           }
00292 
00293         // Multiply matrix times vector
00294         for (unsigned int j=0; j<3; ++j)
00295           for (unsigned int k=0; k<3; ++k)
00296             bez_coords[j] += _bezier_transform[j][k]*phys_coords[k];
00297 
00298         // Store result in _bezier_coeffs
00299         for (unsigned int j=0; j<3; ++j)
00300           _bezier_coeffs[j](i) = phys_coords[j];
00301       }
00302 }
00303 
00304 } // namespace libMesh