postscript_io.C
Go to the documentation of this file.
1 // The libMesh Finite Element Library.
2 // Copyright (C) 2002-2014 Benjamin S. Kirk, John W. Peterson, Roy H. Stogner
3 
4 // This library is free software; you can redistribute it and/or
5 // modify it under the terms of the GNU Lesser General Public
6 // License as published by the Free Software Foundation; either
7 // version 2.1 of the License, or (at your option) any later version.
8 
9 // This library is distributed in the hope that it will be useful,
10 // but WITHOUT ANY WARRANTY; without even the implied warranty of
11 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 // Lesser General Public License for more details.
13 
14 // You should have received a copy of the GNU Lesser General Public
15 // License along with this library; if not, write to the Free Software
16 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
17 
18 // C++ includes
19 #include <ctime>
20 #include <iomanip>
21 #include <iostream>
22 #include <sstream>
23 
24 // Local includes
25 #include "libmesh/postscript_io.h"
26 #include "libmesh/mesh_tools.h"
27 #include "libmesh/elem.h"
28 
29 namespace libMesh
30 {
31 
32 
33 // Transformation map between monomial (physical space) and Bezier bases.
34 const float PostscriptIO::_bezier_transform[3][3] =
35 {
36  {-1.f/6.f, 1.f/6.f, 1.},
37  {-1.f/6.f, 0.5, 1.f/6.f},
38  {0., 1., 0.}
39 };
40 
41 
43  : MeshOutput<MeshBase> (mesh_in),
44  shade_value(0.0),
45  line_width(0.5),
46  //_M(3,3),
47  _offset(0., 0.),
48  _scale(1.0),
49  _current_point(0., 0.)
50 {
51  // This code is still undergoing some development.
52  libmesh_experimental();
53 
54  // Entries of transformation matrix from physical to Bezier coords.
55  // _M(0,0) = -1./6.; _M(0,1) = 1./6.; _M(0,2) = 1.;
56  // _M(1,0) = -1./6.; _M(1,1) = 0.5 ; _M(1,2) = 1./6.;
57  // _M(2,0) = 0. ; _M(2,1) = 1. ; _M(2,2) = 0.;
58 
59  // Make sure there is enough room to store Bezier coefficients.
60  _bezier_coeffs.resize(3);
61 }
62 
63 
64 
66 {
67 }
68 
69 
70 
71 void PostscriptIO::write (const std::string& fname)
72 {
73  // We may need to gather a ParallelMesh to output it, making that
74  // const qualifier in our constructor a dirty lie
75  MeshSerializer serialize(const_cast<MeshBase&>(this->mesh()), !_is_parallel_format);
76 
77  if (this->mesh().processor_id() == 0)
78  {
79  // Get a constant reference to the mesh.
80  const MeshBase& the_mesh = MeshOutput<MeshBase>::mesh();
81 
82  // Only works in 2D
83  libmesh_assert_equal_to (the_mesh.mesh_dimension(), 2);
84 
85  // Create output file stream.
86  // _out is now a private member of the class.
87  _out.open(fname.c_str());
88 
89  // Make sure it opened correctly
90  if (!_out.good())
91  libmesh_file_error(fname.c_str());
92 
93  // The mesh bounding box gives us info about what the
94  // Postscript bounding box should be.
96 
97  // Add a little extra padding to the "true" bounding box so
98  // that we can still see the boundary
99  const Real percent_padding = 0.01;
100  const Real dx=bbox.second(0)-bbox.first(0); libmesh_assert_greater (dx, 0.0);
101  const Real dy=bbox.second(1)-bbox.first(1); libmesh_assert_greater (dy, 0.0);
102 
103  const Real x_min = bbox.first(0) - percent_padding*dx;
104  const Real y_min = bbox.first(1) - percent_padding*dy;
105  const Real x_max = bbox.second(0) + percent_padding*dx;
106  const Real y_max = bbox.second(1) + percent_padding*dy;
107 
108  // Width of the output as given in postscript units.
109  // This usually is given by the strange unit 1/72 inch.
110  // A width of 300 represents a size of roughly 10 cm.
111  const Real width = 300;
112  _scale = width / (x_max-x_min);
113  _offset(0) = x_min;
114  _offset(1) = y_min;
115 
116  // Header writing stuff stolen from Deal.II
117  std::time_t time1= std::time (0);
118  std::tm *time = std::localtime(&time1);
119  _out << "%!PS-Adobe-2.0 EPSF-1.2" << '\n'
120  //<< "%!PS-Adobe-1.0" << '\n' // Lars' PS version
121  << "%%Filename: " << fname << '\n'
122  << "%%Title: LibMesh Output" << '\n'
123  << "%%Creator: LibMesh: A C++ finite element library" << '\n'
124  << "%%Creation Date: "
125  << time->tm_year+1900 << "/"
126  << time->tm_mon+1 << "/"
127  << time->tm_mday << " - "
128  << time->tm_hour << ":"
129  << std::setw(2) << time->tm_min << ":"
130  << std::setw(2) << time->tm_sec << '\n'
131  << "%%BoundingBox: "
132  // lower left corner
133  << "0 0 "
134  // upper right corner
135  << static_cast<unsigned int>( rint((x_max-x_min) * _scale ))
136  << ' '
137  << static_cast<unsigned int>( rint((y_max-y_min) * _scale ))
138  << '\n';
139 
140  // define some abbreviations to keep
141  // the output small:
142  // m=move turtle to
143  // l=define a line
144  // s=set rgb color
145  // sg=set gray value
146  // lx=close the line and plot the line
147  // lf=close the line and fill the interior
148  _out << "/m {moveto} bind def" << '\n'
149  << "/l {lineto} bind def" << '\n'
150  << "/s {setrgbcolor} bind def" << '\n'
151  << "/sg {setgray} bind def" << '\n'
152  << "/cs {curveto stroke} bind def" << '\n'
153  << "/lx {lineto closepath stroke} bind def" << '\n'
154  << "/lf {lineto closepath fill} bind def" << '\n';
155 
156  _out << "%%EndProlog" << '\n';
157  // << '\n';
158 
159  // Set line width in the postscript file.
160  _out << line_width << " setlinewidth" << '\n';
161 
162  // Set line cap and join options
163  _out << "1 setlinecap" << '\n';
164  _out << "1 setlinejoin" << '\n';
165 
166  // allow only five digits for output (instead of the default
167  // six); this should suffice even for fine grids, but reduces
168  // the file size significantly
169  _out << std::setprecision (5);
170 
171  // Loop over the active elements, draw lines for the edges. We
172  // draw even quadratic elements with straight sides, i.e. a straight
173  // line sits between each pair of vertices. Also we draw every edge
174  // for an element regardless of the fact that it may overlap with
175  // another. This would probably be a useful optimization...
177  const MeshBase::const_element_iterator end_el = the_mesh.active_elements_end();
178  for ( ; el != end_el; ++el)
179  {
180  //const Elem* elem = *el;
181 
182  this->plot_linear_elem(*el);
183  //this->plot_quadratic_elem(*el); // Experimental
184  }
185 
186  // Issue the showpage command, and we're done.
187  _out << "showpage" << std::endl;
188 
189  } // end if (this->mesh().processor_id() == 0)
190 }
191 
192 
193 
194 
195 
196 
198 {
199  // Clear the string contents. Yes, this really is how you do that...
200  _cell_string.str("");
201 
202  // The general strategy is:
203  // 1.) Use m := {moveto} to go to vertex 0.
204  // 2.) Use l := {lineto} commands to draw lines to vertex 1, 2, ... N-1.
205  // 3a.) Use lx := {lineto closepath stroke} command at vertex N to draw the last line.
206  // 3b.) lf := {lineto closepath fill} command to shade the cell just drawn
207  // All of our 2D elements' vertices are numbered in counterclockwise order,
208  // so we can just draw them in the same order.
209 
210  // 1.)
211  _current_point = (elem->point(0) - _offset) * _scale;
212  _cell_string << _current_point(0) << " " << _current_point(1) << " "; // write x y
213  _cell_string << "m ";
214 
215  // 2.)
216  const unsigned int nv=elem->n_vertices();
217  for (unsigned int v=1; v<nv-1; ++v)
218  {
219  _current_point = (elem->point(v) - _offset) * _scale;
220  _cell_string << _current_point(0) << " " << _current_point(1) << " "; // write x y
221  _cell_string << "l ";
222  }
223 
224  // 3.)
225  _current_point = (elem->point(nv-1) - _offset) * _scale;
226  _cell_string << _current_point(0) << " " << _current_point(1) << " "; // write x y
227 
228  // We draw the shaded (interior) parts first, if applicable.
229  if (shade_value > 0.0)
230  _out << shade_value << " sg " << _cell_string.str() << "lf\n";
231 
232  // Draw the black lines (I guess we will always do this)
233  _out << "0 sg " << _cell_string.str() << "lx\n";
234 }
235 
236 
237 
238 
240 {
241  for (unsigned int ns=0; ns<elem->n_sides(); ++ns)
242  {
243  // Build the quadratic side
244  AutoPtr<Elem> side = elem->build_side(ns);
245 
246  // Be sure it's quadratic (Edge2). Eventually we could
247  // handle cubic elements as well...
248  libmesh_assert_equal_to ( side->type(), EDGE3 );
249 
250  _out << "0 sg ";
251 
252  // Move to the first point on this side.
253  _current_point = (side->point(0) - _offset) * _scale;
254  _out << _current_point(0) << " " << _current_point(1) << " "; // write x y
255  _out << "m ";
256 
257  // Compute _bezier_coeffs for this edge. This fills up
258  // the _bezier_coeffs vector.
259  this->_compute_edge_bezier_coeffs(side.get());
260 
261  // Print curveto path to file
262  for (unsigned int i=0; i<_bezier_coeffs.size(); ++i)
263  _out << _bezier_coeffs[i](0) << " " << _bezier_coeffs[i](1) << " ";
264  _out << " cs\n";
265  }
266 }
267 
268 
269 
270 
272 {
273  // I only know how to do this for an Edge3!
274  libmesh_assert_equal_to (elem->type(), EDGE3);
275 
276  // Get x-coordinates into an array, transform them,
277  // and repeat for y.
278  float
279  phys_coords[3] = {0., 0., 0.},
280  bez_coords[3] = {0., 0., 0.};
281 
282  for (unsigned int i=0; i<2; ++i)
283  {
284  // Initialize vectors. Physical coordinates are initialized
285  // by their postscript-scaled values.
286  for (unsigned int j=0; j<3; ++j)
287  {
288  phys_coords[j] = (elem->point(j)(i) - _offset(i)) * _scale;
289  bez_coords[j] = 0.; // zero out result vector
290  }
291 
292  // Multiply matrix times vector
293  for (unsigned int j=0; j<3; ++j)
294  for (unsigned int k=0; k<3; ++k)
295  bez_coords[j] += _bezier_transform[j][k]*phys_coords[k];
296 
297  // Store result in _bezier_coeffs
298  for (unsigned int j=0; j<3; ++j)
299  _bezier_coeffs[j](i) = phys_coords[j];
300  }
301 }
302 
303 } // namespace libMesh

Site Created By: libMesh Developers
Last modified: February 07 2014 16:57:06 UTC

Hosted By:
SourceForge.net Logo